Service
Source:
src/AWS/AppRunner/Service.ts
An AWS App Runner service — the zero-infrastructure way to run a container behind an HTTPS endpoint: App Runner provisions, load-balances, scales, and patches the fleet for you. Service creation and deletion are asynchronous and take several minutes; the provider waits (bounded) for operations to settle.
Service is a Platform: alongside the low-level container-image form
(imageRepository), it supports Effect-native implementations — an
inline Effect HTTP program that Alchemy bundles, containerizes, pushes
to a managed ECR repository, and deploys, provisioning the instance and
ECR access roles automatically. Capability bindings (e.g. DynamoDB
GetItem) attach IAM policy statements to the managed instance role.
Creating a Service
Section titled “Creating a Service”Public ECR Image
const service = yield* AppRunner.Service("Hello", { imageRepository: { imageIdentifier: "public.ecr.aws/aws-containers/hello-app-runner:latest", imageRepositoryType: "ECR_PUBLIC", port: "8000", }, instanceConfiguration: { cpu: "256", memory: "512" },});// service.serviceUrl -> "xxxxxxxx.us-west-2.awsapprunner.com"Private ECR Image with Access Role
const service = yield* AppRunner.Service("Api", { imageRepository: { imageIdentifier: `${repository.repositoryUri}:latest`, imageRepositoryType: "ECR", port: "8080", runtimeEnvironmentVariables: { NODE_ENV: "production" }, }, accessRoleArn: accessRole.roleArn, autoDeploymentsEnabled: true,});Effect-Native Services
Section titled “Effect-Native Services”export default class Api extends AppRunner.Service<Api>()( "Api", { main: import.meta.url, port: 3000, instanceConfiguration: { cpu: "256", memory: "512" }, }, Effect.gen(function* () { return { fetch: Effect.gen(function* () { const request = yield* HttpServerRequest; return HttpServerResponse.text("hello from app runner"); }), }; }),) {}Bundling & Tree-shaking
Section titled “Bundling & Tree-shaking”main is bundled with rolldown at deploy time. Top-level calls in the
effect, @effect/*, alchemy, @alchemy.run/*, and
@distilled.cloud/* packages receive #__PURE__ annotations by
default, so anything the service doesn’t use from those packages is
tree-shaken out of the bundle. Any other package — including your own
app — is left untouched unless you list it explicitly.
Treat additional packages as pure
Pass package names (or picomatch globs) via build.pure.packages to
annotate them in addition to the defaults.
{ main: import.meta.url, build: { pure: { packages: ["my-lib", "@my-scope/*"] }, },}Listing a package annotates calls whose result is bound (variable
initializers, exports) — safe anywhere. If a listed package also
declares "sideEffects": false (or []) in its package.json, that
combination opts it into full annotation: top-level calls whose result
is discarded (e.g. router.on("/path", handler) registrations) are
also marked pure and deleted under minification when unused. Only list
a sideEffects: false package if its modules really are free of
meaningful top-level side effects. The effect, alchemy, and
@distilled.cloud defaults declare exactly that, on purpose — their
modules are designed to be fully tree-shakeable.
Disable pure annotations
{ main: import.meta.url, build: { pure: false },}Scaling and Networking
Section titled “Scaling and Networking”const service = yield* AppRunner.Service("Api", { imageRepository: { imageIdentifier: "public.ecr.aws/aws-containers/hello-app-runner:latest", imageRepositoryType: "ECR_PUBLIC", port: "8000", }, autoScalingConfigurationArn: scaling.autoScalingConfigurationArn, networkConfiguration: { egressType: "VPC", vpcConnectorArn: connector.vpcConnectorArn, },});