Immutable versions vs In-place updates
Immutable versions create a completely new deployment for each code change. Once a deployment is registered with Restate, its code cannot change. Restate automatically proxies new requests to the latest version, while ongoing requests continue with their original version until completion. In-place updates modify the code at an existing endpoint without creating a new deployment. While sometimes necessary for critical bug fixes, this approach breaks determinism if not handled carefully. Restate requires the use of immutable versions. They guarantee that your durable executions remain deterministic without requiring you to think about the complexities of breaking existing in-flight invocations. You should in-place updates only in special situations, such as bug fixes.What is a deployment?
A deployment in Restate is a specific, versioned instance of your service code, whether running as an HTTP endpoint, a Lambda function, or another supported environment. Each deployment is immutable by design: once registered, its code and endpoint must not change. An invocation is bound to a specific deployment: it starts and completes within that same deployment. This ensures that in-flight requests always see the code they started with, preserving correctness and determinism.If possible, avoid long-running handlers (days or months).
Otherwise, you need to keep old deployments around for a long time (until all invocations complete).Instead, break work into smaller chunks and chain them via service-to-service calls.For example, instead of a handler that sleeps for hours, have it schedule a new invocation via a delayed message.
It’s possible to resume an invocation on a different deployment.
This is useful if there is a bug in the original deployment’s application code, and you want to move the invocation to a new deployment which contains a fix.
Registering a deployment
After deploying your service, you must register it with Restate so it can be discovered and invoked. You can register a deployment using:- The Restate UI
- The CLI:
- The Admin API:
- For AWS Lambda, use the function ARN instead of a URL (e.g.,
arn:aws:lambda:region:account-id:function:function-name:version
). - If running Restate in Docker, use
host.docker.internal
instead oflocalhost
.
Deployments supporting only HTTP1.1
Some deployments only support HTTP/1.1, and not HTTP/2. This means Restate cannot use bidirectional streaming of journal entries and needs to communicate with the service in request-response mode (learn more). To register such deployments, you need to specify using HTTP/1.1 during registration:Automatic versioning with FaaS platforms
Function-as-a-Service (FaaS) platforms automatically handle immutable versioning through version-specific URLs or ARNs. This makes them ideal for Restate deployments as they eliminate the complexity of manual version management. Have a look at the dedicated deployment docs to learn more:- Vercel: Register the Commit URL so that Restate can address specific Vercel deployments.
- AWS Lambda: When you publish a Lambda function, it automatically creates an immutable version with a unique ARN that never changes.
- Deno Deploy: Register the Preview URLs so that Restate can target specific Deno deployments.
- Cloudflare Workers: Register the Preview URLs so that Restate can target specific Cloudflare deployments.
Automatic versioning with Kubernetes Operator
The Restate Kubernetes operator provides a higher-level abstraction for managing service deployments and their versions automatically. The operator handles the complete versioning lifecycle:- Deploy new versions: Create a new
RestateDeployment
with your updated container image - Automatic registration: The operator registers the new deployment with the Restate cluster
- Traffic routing: New requests automatically route to the latest version
- Graceful draining: The operator monitors older deployments for ongoing invocations
- Auto-scaling to zero: Once drained, older versions automatically scale to zero
Manual deployment management
For non-FaaS deployments or when you need direct control, you can manually manage immutable deployments.Creating immutable deployments
Since deployments are immutable, updates require creating new deployments:1
Deploy new version
Deploy your updated service code to a new endpoint (e.g.,
http://greeter-v2/
).2
Register the new deployment
Then register it with Restate:Restate automatically routes new requests to the latest deployment. Existing requests continue on the original deployment.
3
Monitor deployment status
Check for in-flight invocations on deployments via the UI or CLI.
CLI
4
Remove old deployment
Once all invocations are complete, you can safely remove the old deployment.If you need to force removal before the deployment is fully drained, use the
--force
flag in CLI, or ?force=true
for curl.Virtual Object state persists across versions. Ensure your state schema remains backward compatible.
Removing a service
Restate does not support removing individual services directly. Instead, you must remove the deployment that contains the service. To do this safely, follow the steps below:- Ensure no other handlers or services have business logic that calls the service you’re removing.
- If several services are bundled in the same deployment, you can’t remove only one of them. You have to remove the whole deployment. So make sure that you first deploy the services you want to keep in a separate new deployment.
- Make the service private to avoid accepting new HTTP requests.
- Check whether the service has pending invocations by filtering the invocations on deployment ID in the UI or via
restate services status
, and wait until the service is drained (i.e. no ongoing invocations).
--force
flag in CLI, or ?force=true
for curl.
Advanced: Updating deployments in-place
While deployments should be immutable, critical bugs sometimes require updating deployed code to fix stuck invocations.When This is Needed
If a bug (like a null pointer exception) occurs mid-execution, registering a new deployment only fixes new invocations. Existing stuck invocations need the original deployment fixed.Two Approaches
- Update underlying code at the same URI (does not work for Restate Kubernetes Operator or many FaaS platforms)
- Update deployment endpoint to point to a patched version:
Common Scenarios
Scenario 1: Invocations failing on the active deployment
Scenario 1: Invocations failing on the active deployment
The current deployment handling new invocations has bugs:
- Develop a fix, based on the current deployed version, that resolves the failing invocations. Care should be taken to ensure that the new version has the same behaviour as the old version, for any code paths that in-flight invocations have successfully completed (ie, any changes must be from the point of failure onwards).
- By updating the underlying code or with the update deployment API, change the active deployment to include the fix. Verify that this resolves the issue both for new invocations, and for those already failing.
Scenario 2: Failing invocations on a previous (draining) deployment
Scenario 2: Failing invocations on a previous (draining) deployment
It’s common to notice failing invocations because they are preventing an old deployment from fully draining. In this case there are several concerns; the failing invocations on deployment 1, any failing invocations on deployment 2,
and the potential for new failing invocations to occur on deployment 2 as well. The following steps should be taken:
- Develop a fix as above, based on the version backing deployment 1.
- By updating the underlying code or with the update deployment API, change deployment 1 to include the fix. Verify that this resolves the failing invocations on this deployment.
- Rebase the fix onto the version backing deployment 2.
- By updating the underlying code or with the update deployment API, change deployment 2 to include the fix. Verify that this resolves any failing invocations, if any, new invocations.
It is possible to use the update deployment API to give a deployment the same URI/ARN as another deployment. This is useful where the an appropriate fix for a drained deployment has already been registered as a new deployment.
If this is done, there will be two deployments with the same endpoint, which is otherwise not allowed. It is strongly recommended that you delete one of the two deployments when the failing invocations have been resolved.