MainSDK
Search⌘K
Integrations

AWS Secrets Manager

Use AWS Secrets Manager for MainSDK secrets - IAM role setup, main.yaml, secret references, rotation, local testing and swapping.

1 interface1 driverWritten guide
Updated 2026-10-28

AWS Secrets Manager is one of the cloud drivers behind secrets. Your app reads provider keys such as RESEND_API_KEY from Secrets Manager on the server, and main.yaml refers to them as secret:NAME, never by value. Pick it when your app runs on AWS and you want secrets under the same IAM roles, regions and audit trail as the rest of your account.

Interfaces it serves

Pick AWS Secrets Manager in main.yaml for any of these. Your calls stay the same, and you can swap later.

Before you start

You need an AWS account and permission to manage IAM and Secrets Manager in it.

  1. Choose a region. Secrets Manager stores secrets per AWS region. Put them in the region your app runs in, and keep EU and India apps' secrets in EU and India regions if your data rules ask for it.
  2. Create a secret for each key your app or its drivers need, named the way you will refer to it, such as RESEND_API_KEY. How a secret: name maps to a Secrets Manager secret name or ARN is not defined yet.
  3. Give your app an IAM role. Prefer workload identity: the role your compute already assumes (for example an ECS task role, a Lambda execution role, or an EKS service account mapped to a role). Avoid long-lived access keys.
  4. Grant read access only. Allow the role to read the values of the secrets it needs (in IAM terms, secretsmanager:GetSecretValue on those secrets). If a secret is encrypted with a customer managed KMS key, the role also needs permission to decrypt with that key.

Configure

main.yaml
secrets:
  driver: aws-secrets-manager   # [to be decided] region and other driver settings are not specified yet
email:
  key: secret:RESEND_API_KEY    # suggested name; read from Secrets Manager at startup
pay:
  stripe: { key: secret:STRIPE_SECRET_KEY, webhook: secret:STRIPE_WEBHOOK_SECRET }

Use the local file in development and Secrets Manager in production with overlays:

main.env.dev.yaml
secrets:
  driver: local
main.env.prod.yaml
secrets:
  driver: aws-secrets-manager

A literal value in a field marked secret fails mainsdk check with MAIN-CONFIG-0004.

Use it

Most apps never call secrets.get() directly; drivers receive their keys from secret: references. Call it for credentials your own code uses:

app/api/rates/route.ts
import { auth, http, secrets } from "mainsdk";

export async function GET(req: Request) {
  await auth.require(req);
  const token = await secrets.get("PARTNER_API_TOKEN");
  const res = await http.fetch("https://api.partner.com/v1/rates", {
    headers: { authorization: `Bearer ${token}` },
  });
  return Response.json(await res.json());
}

Local development and testing

  • No AWS account: the local driver reads .mainsdk/secrets.json (git-ignored) and the env driver reads the process environment, so mainsdk dev works with no cloud access.
  • Against real AWS: use a development account or a separate set of secrets, and let the AWS SDK's usual credential chain on your machine supply a short-lived role session.
  • Tests: createTestApp() from @mainsdk/testing runs secrets on its in-memory fake, and chaos.on("secrets", { outage: true }) simulates Secrets Manager being unreachable.
app/lib/partner.test.ts
import { it } from "node:test";
import assert from "node:assert/strict";
import { createTestApp, chaos } from "@mainsdk/testing";
import { secrets } from "mainsdk";

it("serves the last good value when Secrets Manager is down", async () => {
  createTestApp({ main: "./main.yaml" });
  const first = await secrets.get("PARTNER_API_TOKEN");
  chaos.on("secrets", { outage: true });
  assert.equal(await secrets.get("PARTNER_API_TOKEN"), first);
});

What MainSDK adds on top

  • secrets is importable only in server code; a client import fails the build with MAIN-SECRET-0001.
  • Values are redacted from logs, errors and telemetry as [redacted:secret].
  • If Secrets Manager becomes unreachable after a value was read, the last good value is served from memory and MAIN-SECRET-0007 is logged; it is never written to disk.
  • A key in code, a committed env file or the browser bundle fails mainsdk check.

See Secrets for the full contract.

Limits and notes

  • The driver comes with the config-secrets spec (phase 1).
  • Rotation: when Secrets Manager rotates a value, the next secrets.get() after the driver's cache TTL returns the new one, with no restart. The TTL length is not decided yet, and how the driver picks a secret version is not decided yet.
  • Secrets Manager is for credentials. For encrypting records, use keys with AWS KMS.
  • secrets.raw() returns the provider's client for features the interface does not wrap. Each use is logged and listed by mainsdk check.

Swap to or from it

main.yaml
secrets:
  driver: aws-secrets-manager   # was vault

FAQ

Do I need access keys in my app? No. Use the IAM role your compute runs as; MainSDK drivers prefer workload identity over static credentials.

Can I use Secrets Manager only in production? Yes. Use the local or env driver in a development overlay and aws-secrets-manager in main.env.prod.yaml.

What about Parameter Store? It is not a listed driver. Use the env driver if your platform injects Parameter Store values as environment variables.

Next

Open questions

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet