---
title: Deploy to AWS with Pulumi
description: Generate, preview, apply, inspect, and destroy Pulumi stacks from the checked application graph.
pagination: false
sidebar:
  icon: cloud-upload
---

Deploy an application after its local checks and production build pass. Pulumi is the
deployment engine and AWS is the first host integration, but engine, host, application resources, access, and
runtime wiring remain separate roles. See [supported providers](/docs/modules/deployment) for
the full coverage table and [local Docker](/docs/modules/deployment/local-docker) for the default
development and container verification path.

## Pre-setup

Start from an existing application that passes its [local module setup](/docs/modules/integrations#pre-setup).
Install the host/engine below, configure deployment roles, and choose a separate provider profile for
each production resource. A local-only Docker profile cannot supply a production connection.

Supply application secrets through the deployment's runtime environment and declare required
application fields in `defineEnv`. Supply AWS credentials and Pulumi backend access to the deployment
process through their native credential mechanisms; do not add them to the app's public environment
or bundle. Run `bun run relkit doctor --pulumi` to check local tooling before selecting a stack.

> **Authorization and cost required**
>
> These commands can create billable resources. Use an isolated account and stack, confirm the
> target, review every preview, and continue only when authorized to incur cost.

## Run a built application

Run `bun run build` in the development installation first. The build publishes the executable
`.relkit/build/server/index.js`, its graph and manifests, public assets, and any selected immutable
job workers. Copy the complete `.relkit/build` directory into the same relative path in your
production application root.

The build's `package.json` declares exact observed versions of selected runtime integrations and
their required SDKs. Required dependency patches and overrides travel with this manifest; keep the
complete output, including `patches/` when present. Install it before starting from the application root:

```sh title="Terminal — production application root"
cd .relkit/build
bun install --production --network-concurrency 1
cd ../..
NODE_ENV=production bun run --no-env-file .relkit/build/server/index.js
```

The framework runtime is bundled. This production installation does not need the development CLI,
compiler, Inspector application, or unselected SDKs. `relkit start` remains a convenience command
where the CLI is installed; the generated `start` script uses the JavaScript command above.

Supply required application environment values through the process environment. Startup does not
automatically read dotenv files, and build output does not inline their values. `PORT` overrides the
configured listener port. Run from the application root so default local provider state remains at
`.relkit/state`; public assets are resolved beside the built server. Keep existing state and
immutable job generations when replacing build output.

The generated Dockerfile uses `.relkit/build` as its build context. It installs the selected production
manifest and copies the complete server, public assets, graph, and selected worker history. Environment
files, existing local state, and temporary build module links are excluded from that context.

## Install deployment tooling for an existing app

Cloud and deployment default to `none`. The `--cloud aws --deploy pulumi` creation tuple is
currently rejected before staging because public certification is incomplete. Configure deployment
only on an existing app; installing these packages does not make that creation tuple available.

From its development root, install the selected host/engine and deploy-only SDK peers:

{/* Generated by apps/docs/scripts/generate.ts. Do not edit. */}

From this guide's application/package root, install only its selected requirements:

```sh
bun add --dev @pulumi/aws@7.43.0 @pulumi/pulumi@3.259.0 @relkit/aws@0.8.1 @relkit/pulumi@0.8.1
```

Keep these owner-specific versions and the lockfile together. Runtime SDKs belong in `dependencies`; build/type tooling belongs in `devDependencies`. Installing an adapter does not supply its optional SDK peers or enable the feature's configuration.

These development tools generate/preview infrastructure. They do not belong in the built server's
production dependency closure, and none of these installation steps provisions cloud resources.

## Configure deployment roles

Merge the role imports and `deployment` selection into your existing `relkit.config.ts`.
Retain its application ID, environment contract, and provider profiles. This minimal complete
example selects the host and engine; it does not create any resources during import:

```ts title="relkit.config.ts"
/** Select AWS hosting and Pulumi without provisioning resources during import. */
import "@relkit/aws";
import "@relkit/pulumi";
import { defineApp, defineEnv } from "@relkit/app/config";

export default defineApp({
  env: defineEnv({}),
  deployment: { engine: "pulumi", host: "aws" },
});
```

The [complete commerce configuration](https://github.com/rel-kit/relkit/blob/main/examples/commerce/relkit.config.ts)
also binds storage, caching, jobs, and telemetry explicitly.

Keep the existing application's resources and runtime integrations separate from these deployment roles.
Checking and building provision nothing.

## Preview before applying

From that existing configured project, after authorization for the selected account/stack:

```sh title="Terminal — relkit-orders"
bun run check
bun run test
bun run build
bun run relkit doctor --pulumi
bun run relkit deploy init --stack development
bun run relkit deploy preview --stack development
```

Use a separate stack for each isolated environment. Supported backends are Pulumi Cloud, local state, and object
storage URLs. Use repeatable `--config key=value` options for non-secret values and `--config-secret key=value`
for Pulumi secrets.

Preview generates and validates the Pulumi program from the graph. Review create, update, replace, and delete
operations before applying:

```sh title="Terminal — relkit-orders"
bun run relkit deploy up --stack development
bun run relkit deploy outputs --stack development
```

`--non-interactive` (alias `--yes`) approves protected operations for automation; it does not replace review or
authorization.

## Understand resource ownership

An infrastructure wrapper such as `aws(s3(...))` or `aws(redis(...))` may contribute supported lifecycle and
least-privilege access operations. A configured adapter passed directly to `defineApp` contributes runtime wiring
but no resource lifecycle. `docker(adapter)` is development-only and never becomes cloud infrastructure.

Job deployment publishes the immutable task worker and registers schedules only after readiness. Keep the
previous worker generation and its routing keys while it owns accepted runs; deployment does not rewrite run
history or turn a provider without native support into a durable fallback.

The AWS host owns ECS/Fargate hosting, networking, the workload role, load balancing, and CloudWatch routing for
redacted structured stdout. It does not implicitly own application jobs, events, model providers, Sentry, or
OTLP.

## Reconcile and clean up

For an isolated temporary stack:

```sh title="Terminal — relkit-orders"
bun run relkit deploy refresh --stack development
bun run relkit deploy destroy --stack development
```

Confirm the stack before destruction and verify cleanup independently. Never edit the generated Pulumi program
to bypass graph or role validation; repair configuration or integration support, run `check`, and preview again.

{/* Generated by apps/docs/scripts/generate.ts. Do not edit. */}

**Reference and source**

- [`@relkit/app` API](/docs/api/app)
- [`@relkit/jobs` API](/docs/api/jobs)
- [`@relkit/events` API](/docs/api/events)
- [`@relkit/buckets` API](/docs/api/buckets)
- [`@relkit/cache` API](/docs/api/cache)
- [`@relkit/aws` API](/docs/api/integrations/aws)
- [`@relkit/pulumi` API](/docs/api/integrations/pulumi)

- [`examples/commerce/relkit.config.ts`](https://github.com/rel-kit/relkit/blob/main/examples/commerce/relkit.config.ts)
