|Docs

Skipped Builds

Railway can detect when the exact same code has already been built and skip the build entirely, deploying the cached image immediately instead. After you merge a Pull Request, your changes can be live instantly, without waiting for another build.

Screenshot of Rollback Menu

This is different from build layer caching, which speeds up builds by reusing intermediate layers. With skipped builds, no build happens at all: the previously built image is deployed directly.

How it works

When a new deployment is triggered, Railway checks whether an image has already been built from the same source code. If a cached image exists, Railway skips the build and deploys the image directly with the new environment's variables.

A common scenario is when using PR environments:

  1. You open a pull request.
  2. Railway automatically creates a PR environment for you and builds the code.
  3. You make changes to your pull request, and Railway continuously rebuilds and deploys your code to the PR environment.
  4. You merge the pull request. Your PR was up to date, no other commits have landed on the target branch in the meantime.
  5. Railway detects that the merged commit has already been built and deploys the cached image to production: no rebuild required.

This makes deployments feel virtually instant. Bugfixes can be live in seconds, and you can move faster without waiting for redundant builds.

Enabling skipped builds

Skipped builds are disabled by default and can be enabled per service. To enable them, go to your Service Settings and toggle Skipped Builds under Feature Flags.

When builds are not skipped

Certain actions always trigger a full rebuild, even when skipped builds are enabled:

  • Redeploying from the Deployments tab always rebuilds.
  • Deploying the latest commit from the Command Palette (CMD + K → "Deploy Latest Commit") always rebuilds.
  • railway up always uploads and builds your code.

Environment variables and caching

When a cached image is reused, the new environment's variables are applied at runtime. For most applications, this works seamlessly: variables read at startup or from process.env at request time will reflect the correct environment.

However, if your build process inlines environment variable values into the output bundle (for example, NEXT_PUBLIC_* variables in Next.js or VITE_* variables in Vite), the cached image will still contain the values from the original build. This means variables from the previous environment, such as a PR environment, would carry over into production.

Only enable skipped builds when your build output is independent of environment variables. If your build inlines variables, either keep skipped builds disabled or restructure your application as described below.

Optimizing your application for skipped builds

Move build-time side effects to a pre-deploy command

If your build runs tasks that must execute before every deployment, such as database migrations or cache warming, move them to a pre-deploy command. Pre-deploy commands run after the build but before the application starts, and they execute even when the build is skipped.

Inject environment variables at runtime instead of build time

If you serve a frontend from your server, you can inject environment-specific values at runtime instead of inlining them during the build. This keeps the build output environment-independent.

For example, in Next.js, instead of using NEXT_PUBLIC_API_URL (which is inlined at build time), read the variable on the server and pass it to the client:

Your client-side code then reads window.__env.apiUrl instead of process.env.NEXT_PUBLIC_API_URL. The same image works across all environments without rebuilding.