The Best Dagster Hosting Platforms in 2026
The confusing thing about hosting Dagster is that there is no such thing as hosting Dagster. There is hosting a webserver that renders the UI, a daemon that ticks schedules and sensors and drains a run queue, one or more code-location servers that hold your pipeline code behind a gRPC interface, a Postgres that holds every run and every structured event those runs emit, and then — separately, and this is the part that decides your bill — somewhere for each run's actual work to execute. Five things, four of which are long-lived processes, and almost every 'how to deploy Dagster' post treats them as one docker-compose file and moves on.
I'm Ajay, I build PandaStack — a Firecracker microVM platform that shows up near the bottom of this list and is not the right answer for most of the question. We are not a Dagster control plane and have no plans to become one, which means I have no reason to talk you out of the managed offering. What I do have is a lot of scar tissue from the isolation half of the problem: what happens when the code inside a run is not code your team wrote. Everything below is qualitative. I have invented no prices, no SLAs and no benchmarks for anyone but us, and Dagster's own config keys and CLI surface move between minor versions, so treat the snippets as shapes and verify against the docs for the version you are actually running.
The four processes you are actually deploying
Get this diagram right in your head before you shortlist anything, because every hosting option below is really just a different opinion about who runs which of these boxes.
- The webserver (dagster-webserver, the thing that used to be called dagit). Serves the UI and a GraphQL API. Stateless, horizontally scalable, and the least interesting process in the system. It reads almost everything it shows you out of Postgres.
- The daemon (dagster-daemon). Runs schedules, evaluates sensors, drains the run queue if you use a queued run coordinator, evaluates declarative automation / auto-materialize conditions, and monitors runs that died without telling anyone. It is a singleton. More on that in a moment, because it is the single most load-bearing operational fact in this post.
- Code locations. Your pipeline code, loaded into its own process and exposed over gRPC. The webserver and daemon do not import your code; they talk to it. This is why a Dagster deploy is a redeploy rather than a file sync, and it is both the best and the most annoying design decision in the system.
- Storage — in practice, Postgres. Run storage, event log storage and schedule storage. Not optional in any deployment you would page someone about.
- And then run compute: the process (or container, or pod, or VM) that each individual run executes in, which is governed by your run launcher and executor and which is where essentially all of your money goes.
The reason this list matters more than a feature grid is that hosting platforms are good at running the first kind of thing — a long-lived web process — and bad at running the second and the fifth. A platform that scales your service to zero when no HTTP arrives will happily put your daemon to sleep, and a sleeping daemon does not fire schedules. A platform that gives you exactly one process per service makes you buy four services before you have run a single asset.
The daemon is a singleton, and that shapes your whole deployment
You are meant to run one dagster-daemon. Not two for redundancy, not one per availability zone. The daemon's loops — schedule ticks, sensor evaluation, run-queue dequeuing — are not designed around a distributed lock you can casually rely on to make a second copy safe, and the failure mode of getting this wrong is not a crash. It is duplicate runs: the same schedule tick materialising the same asset twice, two writers landing in the same warehouse table, and a data-quality incident three days later that nobody traces back to a deployment topology decision.
That one constraint cascades into four things you will otherwise discover the hard way.
- Your deploy strategy for the daemon is stop-then-start, not rolling. A rolling deploy that briefly runs old and new daemons together is exactly the overlap you are trying to avoid. In Kubernetes this means a Recreate strategy and a replica count of one, not a rollingUpdate.
- The daemon is a single point of failure by design, so what you actually need is fast detection and fast restart, not redundancy. Dagster surfaces daemon health in the UI, and there is a heartbeat you can alert on. Alert on it. A daemon that has been dead for six hours looks exactly like a quiet Tuesday.
- The daemon can never scale to zero. This disqualifies more platforms than anything else in this post. Scale-to-zero is a lovely property for the webserver, which nobody looks at overnight, and a catastrophic one for the component whose entire job is to notice that it is 3am.
- Missed ticks are a policy decision you should make on purpose. If the daemon is down across a schedule's tick, what should happen when it comes back — catch up, or skip? Dagster gives you controls here; the default behaviour is worth reading carefully rather than assuming, because 'catch up' and 'skip' are both correct answers depending on whether your pipeline is idempotent.
Postgres is not optional, and the event log is the hot table
Dagster defaults to SQLite inside DAGSTER_HOME, which is genuinely good for local development with dagster dev and genuinely unsuitable for anything shared. The moment you have a webserver process and a daemon process and a run process all wanting to read and write the same state, you need a real database, and in practice that means Postgres.
There are three logical stores — run storage, event log storage, schedule storage — and you almost always point all three at the same Postgres instance. The one worth understanding is the event log, because it is not a log in the sense of text you grep later. It is the structured record of everything that happened: every step start and success, every asset materialisation, every output, every observation, every expectation result. The UI is a read layer over it. Asset lineage, the run timeline, the materialisation history on an asset page — all of that is queries against this table.
Which gives you the two things nobody warns you about. First, event log volume scales with steps and asset materialisations, not with runs, so a pipeline that fans out to two thousand partitions writes vastly more than its run count suggests. Second, Postgres connections scale with concurrency: every concurrent run process opens its own connections, and 'we raised max_concurrent_runs' is a well-trodden path to exhausting a small managed instance's connection limit. Put a pooler in front of it if your run concurrency is anywhere near your connection ceiling.
# $DAGSTER_HOME/dagster.yaml
# The instance config the webserver, the daemon and every run process all read.
# Module paths and config keys shift between Dagster versions -- check the docs
# for the version you actually run before copying this wholesale.
storage:
postgres:
postgres_db:
username:
env: DAGSTER_PG_USERNAME
password:
env: DAGSTER_PG_PASSWORD
hostname:
env: DAGSTER_PG_HOST
db_name:
env: DAGSTER_PG_DB
port: 5432
params:
# Managed Postgres providers generally require TLS. Say so explicitly.
sslmode: require
# Queue runs instead of launching them the instant a schedule fires, so a
# backfill cannot open four hundred connections to your warehouse at once.
run_coordinator:
module: dagster.core.run_coordinator
class: QueuedRunCoordinator
config:
max_concurrent_runs: 20
tag_concurrency_limits:
# Every run tagged for the warehouse shares four slots, regardless of
# which code location or asset group it came from.
- key: "resource"
value: "warehouse"
limit: 4
# Where each run's process goes. This is the decision that dominates cost.
run_launcher:
module: dagster_docker
class: DockerRunLauncher
config:
env_vars:
- DAGSTER_PG_USERNAME
- DAGSTER_PG_PASSWORD
- DAGSTER_PG_HOST
- DAGSTER_PG_DB
network: dagster_network
container_kwargs:
auto_remove: true
# stdout/stderr per step. The local default writes to the instance's disk,
# which on ephemeral storage means your logs die with the container.
compute_logs:
module: dagster_aws.s3.compute_log_manager
class: S3ComputeLogManager
config:
bucket: my-dagster-compute-logs
prefix: compute-logs
# Notice runs whose process vanished without reporting a failure.
run_monitoring:
enabled: true
# Tick history grows forever unless you tell it not to.
retention:
schedule:
purge_after_days: 90
sensor:
purge_after_days: 30Code locations: why a Dagster deploy is a redeploy
This is the design decision that most distinguishes Dagster operationally from the orchestrator most of your team has used before. Dagster does not scan a folder of Python files and import them into the scheduler. Your definitions live in a code-location server — a separate process, started with the Dagster CLI, exposing a gRPC interface — and the webserver and daemon connect to it as clients. A workspace file tells them where those servers are.
# workspace.yaml -- what the webserver and daemon connect to.
load_from:
- grpc_server:
host: analytics-code-server
port: 4000
location_name: analytics
- grpc_server:
host: ml-code-server
port: 4000
location_name: ml_features
# Each of those servers is started next to your code, roughly like:
# dagster api grpc -h 0.0.0.0 -p 4000 -m analytics.definitions
# Newer versions also ship a long-lived code server command that supports
# reloading definitions without a full restart -- check your version's CLI.The upside is real and it is the thing Airflow shops envy. Each code location is its own process with its own image and its own dependency set, so the ML team's pandas pin and the finance team's ancient vendor SDK never meet. A code location that fails to import shows up as one broken location in the UI instead of taking the scheduler down. And because your code is not in the same process as the daemon, a memory leak in a definition does not leak into the component that must never die.
The downside is the flip side of the same coin: changing pipeline code means redeploying a server, not copying a file. You need a build-and-deploy pipeline per code location, images to store, and a plan for the moment when the code server is running new definitions while the webserver still has the old ones cached. Version skew matters here in a way it does not with a folder of DAGs — running a code location on a Dagster library version far from your webserver and daemon is asking for gRPC-level surprises, so pin them together and upgrade them together.
Airflow makes you share one Python environment and pay for it in dependency conflicts. Dagster makes you deploy several and pay for it in CI pipelines. Pick which bill you would rather receive.
Run launcher vs executor: the choice that dominates cost and ops
These two words get used interchangeably in conversation and they are not the same axis, which causes a specific and expensive confusion. The run launcher decides where the process for a whole run goes. The executor decides how the individual steps inside that run are executed once the run process exists. You configure the launcher once at instance level; you can configure the executor per job or per asset selection.
- Default run launcher — the run process is spawned by the code-location server itself. Zero infrastructure, near-zero startup latency, and all your runs share one machine's memory and CPU. Perfect for a single-VM deployment; a noisy-neighbour incident waiting to happen once one run wants 12GB.
- Docker run launcher — one container per run, on a Docker host. Real resource limits, real image-level dependency isolation, startup measured in low seconds. The natural fit for a one-box or small-fleet deployment.
- Kubernetes run launcher — one Kubernetes Job per run. Per-run resource requests, node autoscaling, and the whole cluster's scheduling machinery. Startup pays pod scheduling plus image pull, which is fine for a fifteen-minute run and a poor trade for a four-second one.
- ECS run launcher — one ECS task per run, for AWS shops who deliberately do not run Kubernetes. Same shape as the Kubernetes launcher with AWS's task-startup characteristics and IAM task roles instead of service accounts.
Then the executor, inside the run: in-process runs every step sequentially in the run's own process, which is the right answer more often than people admit. Multiprocess forks a process per step and is the usual default. And there are executors that turn every step into its own pod, container, or Celery task, which is where the interesting cost question lives.
Here is the trap. Per-step isolation multiplies your fixed startup cost by your step count. A hundred-step asset graph where each step launches a pod that pulls a two-gigabyte image spends more wall-clock time scheduling and pulling than computing, and you pay for all of it. The heuristic I would offer: isolate at the run level by default, and only isolate at the step level when individual steps have genuinely different resource shapes — one step needs a GPU, one needs 64GB, one needs neither — or when the steps must not be able to see each other's memory.
The isolation question, which is not the same as the resource question
Everything above is about resource isolation: making sure one step's memory appetite does not starve another. There is a second question that looks similar and has a completely different answer, and it is increasingly the one that matters. What if the code inside the run is not yours?
This is not hypothetical for a growing set of Dagster deployments. A run that pip-installs whatever a requirements file says. A dbt project a customer connected. A transform an analyst wrote and an LLM finished. A partner's scoring function. A notebook uploaded through your product's UI. In every one of those cases the code executes with your run process's credentials — the warehouse connection, the object-storage token, the Postgres password sitting in an environment variable that any Python process can read.
A container gives you good resource limits and a shared kernel. For code you wrote, that is fine and I am not going to pretend otherwise. For code you did not write, the honest position is that a container is a packaging boundary that happens to have some security properties, and the isolation you actually want is a hypervisor. That is the specific problem a microVM per run solves, and it is the only part of this post where I think we have something genuinely better rather than merely different.
The hosting options, honestly
1. Dagster+ Serverless
The first-party managed offering in its fully-hosted form: Dagster Labs runs the control plane and the compute. You push code, they build and run it. No daemon to keep alive, no Postgres to size, no code-location servers to operate, and features like branch deployments — a full ephemeral Dagster environment per pull request — that are genuinely hard to build yourself.
This is the correct default for most teams, and I say that as a competitor to nothing in the sentence. The reasons not to pick it are specific rather than general: your data or your code cannot leave your infrastructure for compliance reasons; your runs need machine shapes or long durations that a serverless product does not offer; or you need something in the run environment — a GPU, a specific kernel feature, a VPC-private data source — that the hosted runtime does not expose. Check the current resource limits, run-duration ceilings and networking options against Dagster's documentation, because those are exactly the constraints that decide this and exactly the ones that change.
2. Dagster+ Hybrid
The same hosted control plane, but the compute runs in your infrastructure. You deploy an agent — there are agent flavours for Kubernetes, ECS, Docker and local processes — and it launches code servers and runs inside your own environment while metadata flows to Dagster's control plane.
This is the setting most serious data platform teams end up in, and the trade is clean: you keep data locality, VPC access and machine choice, and you hand off the parts that are pure toil — the daemon's liveness, the metadata database, the UI, upgrades of the control plane. What you still own is real, though. The agent is a process you keep alive. Your code locations are still your build pipelines and your images. Your runs still land on capacity you provisioned and pay for. Hybrid is a large reduction in operational surface, not the elimination of it, and teams who budget for it as 'managed' are sometimes surprised by how much cluster work remains.
3. Kubernetes via the official Helm chart
The maximum-control self-hosted option, and for a team that already runs Kubernetes well, a genuinely good one. The chart deploys the webserver, the daemon, your code-location deployments and optionally a Postgres, and wires the Kubernetes run launcher so each run becomes a Job. You choose versions, you set any instance config key you like, you get per-run resource requests and cluster autoscaling for free, and your secrets come from wherever your cluster's secrets already come from.
Three things to get right, in order. Do not use the chart's bundled in-cluster Postgres for production — point it at a managed instance, because the metadata database is the one component whose loss is unrecoverable and whose backups you do not want to be inventing. Set the daemon's deployment to one replica with a recreate strategy. And be deliberate about the executor: the default of one Job per run plus a per-step executor is a lot of pod churn, and for short steps the in-run multiprocess executor is faster and cheaper. The standing rule applies here as everywhere — this is right if Kubernetes is already load-bearing for you, and wrong if you would be adopting Kubernetes in order to run Dagster.
4. One VM with docker-compose or systemd
The under-rated option, and the one I would push most small teams toward. A webserver, a daemon, one or two code servers and a managed Postgres will comfortably handle the workload of most companies who believe they need a cluster. It is one machine, one set of logs, one thing to restart, and the Docker run launcher gives you per-run containers without a scheduler in the middle.
The ceiling is where you would expect. You are bounded by one machine's RAM and CPU, so a run that wants 30GB is a resize rather than a scheduling decision. Bursty backfills queue instead of spreading. And your daemon's availability is your VM's availability, which is fine if you use the run queue and idempotent pipelines and merely awkward if a two-hour outage means a missed SLA. Run the daemon under a process supervisor with a restart policy and alert on the heartbeat; that combination gets you most of the way to what an HA setup would have bought.
# /etc/systemd/system/dagster-webserver.service
# Stateless, restartable, safe to run more than one of.
[Unit]
Description=Dagster webserver
After=network-online.target
[Service]
User=dagster
Environment=DAGSTER_HOME=/opt/dagster/home
EnvironmentFile=/etc/dagster/env # DAGSTER_PG_* live here, 0600, not in git
WorkingDirectory=/opt/dagster/app
ExecStart=/opt/dagster/venv/bin/dagster-webserver \
-h 0.0.0.0 -p 3000 \
-w /opt/dagster/app/workspace.yaml
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
# ---------------------------------------------------------------------------
# /etc/systemd/system/dagster-daemon.service
# Schedules, sensors, run queue, run monitoring. EXACTLY ONE of these.
# Never a rolling deploy: stop the old one before the new one starts.
[Unit]
Description=Dagster daemon
After=network-online.target
[Service]
User=dagster
Environment=DAGSTER_HOME=/opt/dagster/home
EnvironmentFile=/etc/dagster/env
WorkingDirectory=/opt/dagster/app
ExecStart=/opt/dagster/venv/bin/dagster-daemon run
Restart=always
RestartSec=5
# Give in-flight bookkeeping a moment; do not SIGKILL a mid-tick daemon.
TimeoutStopSec=30
[Install]
WantedBy=multi-user.targetBoth units read the same DAGSTER_HOME, which is the directory holding dagster.yaml — that is how the webserver, the daemon and every launched run agree on which Postgres and which run launcher they are using. Getting DAGSTER_HOME wrong on one of them is the classic self-host bug: everything starts cleanly, and the daemon writes to a SQLite file nobody is reading.
5. ECS, Cloud Run and friends
Container platforms that are not Kubernetes are a reasonable middle ground, with one caveat that eliminates some of them outright. The webserver is a perfect fit — an HTTP service, stateless, scale it however you like. The code servers are fine, as long as the platform will let the webserver and daemon reach them over gRPC on an internal address. The daemon is where platforms fail the test: it takes no HTTP traffic, so a request-driven autoscaler will scale it to zero, and any platform that will not guarantee you exactly one always-on instance of a non-HTTP process is disqualified.
ECS passes cleanly — a service with desired count one, plus the ECS run launcher so runs become tasks with their own IAM roles. Cloud Run and its equivalents pass only if you use whatever their always-on, no-scale-to-zero worker construct is called, and you should confirm that construct's semantics before committing rather than after the first missed schedule. On any of them, the metadata Postgres is a separate managed service you provision yourself, and the connection ceiling on the small tier is closer than you think.
6. A microVM per run (where we fit)
Read this as an interested party's description, because it is one. PandaStack is an open-source Firecracker microVM platform: managed PostgreSQL 16, app hosting with scale-to-zero, serverless functions with cron, and sandboxes that start from a snapshot with a create p50 around 179ms. Pricing is $0.054 per vCPU-hour and $0.0162 per GiB-hour, billed on what runs.
The unglamorous half is that Dagster's long-lived processes deploy here like they deploy anywhere else with a real Linux userspace: the webserver and code servers as apps from git, the daemon as an always-on app, and the metadata database as a managed Postgres. The important caveat is the same one that applies to every platform in this post, and it applies to us with full force — the webserver may sleep when nobody is looking at it, the daemon absolutely may not. Do not put the daemon on scale-to-zero. I would rather say that plainly than have you discover it.
The half that is actually differentiated is the run. A microVM per run is hardware-level isolation with its own kernel, so a run that pip-installs an arbitrary package, executes a customer-supplied transform, or runs LLM-generated Python cannot reach the host, the other runs, or the credentials in anyone else's environment. Start time is short enough that this is a per-run decision rather than a per-tenant one, and because the VM dies at the end of the run, cleanup is guaranteed rather than best-effort.
Now the honest limits. There is no first-party PandaStack run launcher in Dagster's ecosystem. In practice you do this from inside your assets and ops — the op calls our API, creates a sandbox, ships the untrusted work into it, streams back results and destroys it — which is a resource and a helper function, not an integration you install. That pattern works well and composes with any of the hosting options above, including Dagster+ Hybrid; you can run the orchestrator wherever you like and only send the dangerous steps to us. But if what you want is a managed Dagster control plane, we are not that, and Dagster+ is the honest recommendation.
Side by side
- Dagster+ Serverless — Model: control plane and compute both hosted; you push code. Ops burden: essentially none. Watch: run duration and resource ceilings, and whether your data is allowed to leave your infrastructure. Best for: most teams, and nearly every team without a dedicated platform engineer.
- Dagster+ Hybrid — Model: hosted control plane, agent and compute in your infrastructure. Ops burden: moderate — you keep the agent alive and own your code-location builds and capacity. Watch: the amount of cluster work that remains after 'managed'. Best for: data teams with VPC-private sources, compliance constraints or specific machine requirements.
- Kubernetes via the Helm chart — Model: everything self-hosted, one Job per run. Ops burden: inherits your cluster's cost; high if the cluster is new. Watch: bundled Postgres in production, daemon replica count and strategy, per-step pod churn. Best for: teams already running Kubernetes with working GitOps.
- One VM with docker-compose or systemd — Model: four processes on a box plus managed Postgres and a Docker run launcher. Ops burden: low and legible. Watch: single-machine RAM ceiling and daemon availability. Best for: the large majority of companies who think they need a cluster and do not.
- ECS / Cloud Run style — Model: containerised services, run launcher turning runs into tasks. Ops burden: low-moderate. Watch: the daemon must be pinned to exactly one always-on instance; scale-to-zero silently breaks scheduling. Best for: AWS or GCP shops who deliberately avoid Kubernetes.
- microVM per run (PandaStack) — Model: orchestrator hosted anywhere; risky runs execute in a Firecracker VM with its own kernel. Ops burden: an API call inside your op, plus normal app hosting for the long-lived processes. Watch: no first-party run launcher; the daemon must not sleep. Best for: platforms running code they did not write.
The five things that actually bite in production
Independent of which option you pick. I have watched every one of these cost someone a day.
- Compute logs on ephemeral disk. Per-step stdout and stderr go to the compute log manager, and the default writes them to local disk. On any platform where the run container is disposable, that means the logs for the failed run you are investigating were deleted along with the container that failed. Configure an object-storage compute log manager before your first production incident, not after it.
- DAGSTER_HOME drift. The webserver, the daemon and every launched run must all read the same dagster.yaml. When one of them does not, it silently falls back to its own local storage and you get a UI that shows no runs while runs are demonstrably happening.
- Sensor cursors and evaluation intervals. Sensors are a polling loop with a cursor, and the two ways they go wrong are 'ran too often and hammered an upstream API' and 'the cursor advanced past events that were never processed'. Both are quiet. Neither shows up as a failed run.
- Event log growth. Partitioned assets and large fan-outs write far more events than the run count implies. Set retention on tick history, keep an eye on the size of the event log tables, and size the metadata Postgres one tier above what a demo suggests. The UI feeling slow is almost always this.
- Schedule timezones and the concurrency you did not set. A schedule with no explicit timezone will eventually surprise you around a DST boundary, and an instance with no run-queue limits will happily launch a hundred simultaneous runs the first time someone triggers a backfill over a year of daily partitions. Set both explicitly.
How to choose, in ten minutes
- Ask whether your code and data may leave your infrastructure. If yes, start at Dagster+ Serverless and only leave it for a concrete blocker. If no, you are choosing between Hybrid and self-hosting, and the rest of this list applies.
- Write down the largest single run you will need — RAM, wall-clock, and whether it needs a GPU or a VPC-private endpoint. That number eliminates more options than any feature comparison will.
- Decide where the daemon lives and how you will know it stopped. If your candidate platform cannot promise exactly one always-on non-HTTP process with a heartbeat you can alert on, it is not a candidate.
- Pick the run launcher before the executor, and default to run-level isolation. Only reach for per-step pods when steps genuinely differ in resource shape. Per-step isolation multiplies startup cost by step count.
- Ask the isolation question explicitly: will any run ever execute code that a customer, a partner, or a model wrote? If yes, decide now whether a shared kernel is acceptable, because retrofitting a hypervisor boundary later means rewriting the ops that matter most.
- Then prove it with a spike, not a spreadsheet. Deploy the candidate, point it at a deliberately undersized Postgres, and run a backfill over a year of daily partitions. You will learn more in an afternoon than in a week of vendor pages.
The short version
Dagster+ Serverless if your data can leave and you would rather ship pipelines than operate four processes — which is most teams, and there is no shame in it. Dagster+ Hybrid if you need data locality or specific machines but want someone else responsible for the daemon and the metadata database. Kubernetes with the Helm chart if the cluster already exists and someone already knows it. One VM with a managed Postgres if you are smaller than you think you are, which is more common than the conference talks suggest. And a microVM per run, from us or from anyone, for the specific case where the code inside the run is not code you wrote.
Whichever you choose, three decisions will still be the ones that matter in a year, and they are the same on every platform: the daemon is a singleton that must never sleep and must be alerted on, the metadata Postgres is the component whose loss you cannot recover from, and your compute logs belong in object storage rather than on a disk that disappears. Get those right and the hosting question stops being the interesting one — which, for an orchestrator, is exactly the goal.
Frequently asked questions
Does Dagster require a Postgres database?
For any shared deployment, yes. Dagster defaults to SQLite inside DAGSTER_HOME, which is fine for local development with dagster dev but unsuitable once a webserver process, a daemon process and separate run processes all need to read and write the same state. Production deployments point run storage, event log storage and schedule storage at a single Postgres instance via the storage block in dagster.yaml. Size it above what a demo suggests: the event log grows with steps and asset materialisations rather than with run count, and every concurrent run opens its own connections, so run concurrency is what exhausts a small instance's connection limit.
Can I run more than one dagster-daemon for high availability?
No — the daemon is designed as a singleton, and running two is not a redundancy strategy, it is a duplicate-execution bug. The failure mode is not a crash but the same schedule tick firing twice, two writers landing in the same table, and a data-quality incident nobody traces back to deployment topology. The practical approach is fast detection and fast restart instead of redundancy: exactly one replica, a recreate rather than rolling deploy strategy so old and new never overlap, a process supervisor with a restart policy, and an alert on the daemon heartbeat. A dead daemon looks exactly like a quiet night otherwise.
What is the difference between a run launcher and an executor in Dagster?
They are two different axes that get used interchangeably in conversation. The run launcher decides where the process for an entire run goes — the default launcher spawns it on the code-location server, while the Docker, Kubernetes and ECS launchers give each run its own container, Job or task. The executor decides how individual steps inside that run execute once the run process exists: sequentially in-process, across forked processes, or as one pod or container per step. The launcher is instance-level config; the executor can be set per job. The cost trap is at the step level, because per-step isolation multiplies fixed startup cost by step count.
Should I choose Dagster+ Serverless or Hybrid?
Serverless hosts both the control plane and the compute, so you push code and operate nothing — the right default for most teams. Hybrid hosts the control plane while an agent you run launches code servers and runs inside your own infrastructure. Choose Hybrid for a concrete blocker rather than on principle: data or code that may not leave your environment, VPC-private data sources, or runs needing machine shapes and durations a serverless runtime does not offer. Budget honestly for what Hybrid leaves you owning — the agent's liveness, your code-location build pipelines, and the capacity your runs land on. Verify current limits against Dagster's documentation.
How do I isolate untrusted or customer-supplied code in a Dagster run?
Recognise first that resource isolation and security isolation are different problems. Per-step containers and pod resource limits stop one step starving another, but a container shares the host kernel and the run process's credentials — the warehouse connection, object-storage tokens and database passwords sitting in environment variables any Python process can read. When a run pip-installs arbitrary packages, executes a customer's transform or runs model-generated Python, the boundary you want is a hypervisor. Running that step in a microVM with its own kernel — created from inside the op and destroyed when the run ends — gives hardware-level isolation and guaranteed cleanup.
Keep reading
- Best Apache Airflow hosting platforms in 2026 — The same question for the other orchestrator — where the metadata DB and shared-worker dependency hell dominate instead.
- The best durable execution platforms in 2026 — Read this if your asset graph is really a long-running business process wearing a DAG costume.
- Top 7 Celery hosting platforms in 2026 — The always-on-worker hosting problem in its purest form — the same trap that disqualifies platforms for the daemon.
- Best managed Postgres providers in 2026 — For the metadata database, which is the one component whose loss you cannot recover from.
- Per-tenant isolation for dbt transformations — The deeper version of the customer-supplied-transform problem, with the ops-level pattern spelled out.
- Firecracker sandboxes on PandaStack — What a microVM per run actually is, including start times and pricing.
49ms p50 cold start. Fork, snapshot, and scale to zero.