Skip to content
RELKIT
Esc
↑↓navigate↵open⌘Jpreview
On this page

Deploy to AWS with Pulumi

Generate, preview, apply, inspect, and destroy Pulumi stacks from the checked application graph.

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 for the full coverage table and local Docker for the default development and container verification path.

Pre-setup

Start from an existing application that passes its local module 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.

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:

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:

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

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:

/** 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 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:

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:

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:

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.

Reference and source