@aws/nx-plugin-mcp 0.119.0 → 0.121.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/bin/aws-nx-mcp.js +23 -35
  2. package/docs/guides/astro-docs.mdx +142 -0
  3. package/docs/guides/connection/py-agent-a2a.mdx +105 -0
  4. package/docs/guides/connection/py-agent-mcp.mdx +147 -0
  5. package/docs/guides/connection/react-agui.mdx +240 -0
  6. package/docs/guides/connection/react-fastapi.mdx +1476 -0
  7. package/docs/guides/connection/react-py-agent.mdx +198 -0
  8. package/docs/guides/connection/react-smithy.mdx +1355 -0
  9. package/docs/guides/connection/react-trpc.mdx +447 -0
  10. package/docs/guides/connection/react-ts-agent.mdx +198 -0
  11. package/docs/guides/connection/smithy-rdb.mdx +161 -0
  12. package/docs/guides/connection/trpc-rdb.mdx +127 -0
  13. package/docs/guides/connection/ts-agent-a2a.mdx +106 -0
  14. package/docs/guides/connection/ts-agent-mcp.mdx +144 -0
  15. package/docs/guides/connection/ts-agent-rdb.mdx +141 -0
  16. package/docs/guides/connection/ts-mcp-server-rdb.mdx +135 -0
  17. package/docs/guides/connection.mdx +126 -0
  18. package/docs/guides/docker-bundling.mdx +403 -0
  19. package/docs/guides/fastapi.mdx +509 -0
  20. package/docs/guides/license.mdx +293 -0
  21. package/docs/guides/nx-generator.mdx +588 -0
  22. package/docs/guides/py-agent.mdx +483 -0
  23. package/docs/guides/py-mcp-server.mdx +161 -0
  24. package/docs/guides/python-lambda-function.mdx +207 -0
  25. package/docs/guides/python-project.mdx +228 -0
  26. package/docs/guides/react-website-auth.mdx +216 -0
  27. package/docs/guides/react-website.mdx +421 -0
  28. package/docs/guides/runtime-config.mdx +312 -0
  29. package/docs/guides/terraform-project.mdx +317 -0
  30. package/docs/guides/trpc.mdx +816 -0
  31. package/docs/guides/ts-agent.mdx +436 -0
  32. package/docs/guides/ts-lambda-function.mdx +218 -0
  33. package/docs/guides/ts-mcp-server.mdx +169 -0
  34. package/docs/guides/ts-nx-plugin.mdx +159 -0
  35. package/docs/guides/ts-rdb.mdx +759 -0
  36. package/docs/guides/ts-smithy-api.mdx +661 -0
  37. package/docs/guides/typescript-infrastructure.mdx +408 -0
  38. package/docs/guides/typescript-project.mdx +312 -0
  39. package/docs/guides/workspace.mdx +181 -0
  40. package/docs/snippets/agent/architecture.mdx +72 -0
  41. package/docs/snippets/agent/bedrock-deployment.mdx +172 -0
  42. package/docs/snippets/agent/runtime-arn.mdx +64 -0
  43. package/docs/snippets/api/api-architecture.mdx +93 -0
  44. package/docs/snippets/api/api-choice-note.mdx +6 -0
  45. package/docs/snippets/api/cors-configuration-cdk-note.mdx +25 -0
  46. package/docs/snippets/api/cors-configuration-terraform-note.mdx +28 -0
  47. package/docs/snippets/api/shared-constructs.mdx +38 -0
  48. package/docs/snippets/api/type-safe-api-integrations.mdx +643 -0
  49. package/docs/snippets/api/waf-configuration.mdx +37 -0
  50. package/docs/snippets/connection/a2a-infrastructure.mdx +63 -0
  51. package/docs/snippets/connection/lambda-rdb-ssl-requirements.mdx +40 -0
  52. package/docs/snippets/connection/mcp-server-rdb-ssl-requirements.mdx +35 -0
  53. package/docs/snippets/connection/rdb-api-infrastructure.mdx +72 -0
  54. package/docs/snippets/connection/react-agent-infrastructure.mdx +61 -0
  55. package/docs/snippets/connection/strands-agent-rdb-ssl-requirements.mdx +35 -0
  56. package/docs/snippets/lambda-function/architecture.mdx +36 -0
  57. package/docs/snippets/lambda-function/deploying-your-function.mdx +118 -0
  58. package/docs/snippets/mcp/architecture.mdx +58 -0
  59. package/docs/snippets/mcp/assistant-docs.mdx +10 -0
  60. package/docs/snippets/mcp/bedrock-deployment.mdx +167 -0
  61. package/docs/snippets/mcp/config.mdx +13 -0
  62. package/docs/snippets/mcp/configuration-py.mdx +42 -0
  63. package/docs/snippets/mcp/configuration-ts.mdx +53 -0
  64. package/docs/snippets/mcp/observability.mdx +8 -0
  65. package/docs/snippets/mcp/shared-constructs.mdx +32 -0
  66. package/docs/snippets/pdk-migration/example/01-migrate-api.mdx +602 -0
  67. package/docs/snippets/pdk-migration/example/02-migrate-website.mdx +915 -0
  68. package/docs/snippets/pdk-migration/example/03-migrate-infra.mdx +161 -0
  69. package/docs/snippets/pdk-migration/example/04-deploy.mdx +229 -0
  70. package/docs/snippets/pdk-migration/faq/aws-arch.mdx +17 -0
  71. package/docs/snippets/pdk-migration/faq/cdk-graph.mdx +29 -0
  72. package/docs/snippets/pdk-migration/faq/infrastructure-python-java.mdx +19 -0
  73. package/docs/snippets/pdk-migration/faq/pdk-nag.mdx +15 -0
  74. package/docs/snippets/pdk-migration/faq/pipeline.mdx +15 -0
  75. package/docs/snippets/pdk-migration/faq/type-safe-api.mdx +310 -0
  76. package/docs/snippets/pdk-migration/faq/use-of-projen.mdx +15 -0
  77. package/docs/snippets/prerequisites.mdx +20 -0
  78. package/docs/snippets/required-prerequisites.mdx +12 -0
  79. package/docs/snippets/shared-constructs.mdx +40 -0
  80. package/docs/snippets/tools/acurl.mdx +73 -0
  81. package/docs/snippets/ts-bundle.mdx +14 -0
  82. package/package.json +1 -1
  83. package/src/py/agent/schema.json +1 -1
  84. package/src/py/fast-api/schema.json +2 -2
  85. package/src/py/mcp-server/schema.json +1 -1
  86. package/src/smithy/ts/api/schema.json +2 -2
  87. package/src/trpc/backend/schema.json +2 -2
  88. package/src/ts/agent/schema.json +1 -1
  89. package/src/ts/mcp-server/schema.json +1 -1
@@ -0,0 +1,135 @@
1
+ ---
2
+ title: MCP Server to Relational Database
3
+ description: Connect a TypeScript MCP Server to a Relational Database
4
+ when:
5
+ sourceType: ts#mcp-server
6
+ targetType: ts#rdb
7
+ ---
8
+ import { FileTree } from '@astrojs/starlight/components';
9
+ import Link from '@components/link.astro';
10
+ import RunGenerator from '@components/run-generator.astro';
11
+ import GeneratorParameters from '@components/generator-parameters.astro';
12
+ import NxCommands from '@components/nx-commands.astro';
13
+ import Infrastructure from '@components/infrastructure.astro';
14
+ import Snippet from '@components/snippet.astro';
15
+
16
+ The `connection` generator wires a <Link path="guides/ts-mcp-server">TypeScript MCP Server</Link> to a <Link path="guides/ts-rdb">Relational Database</Link> project, making a Prisma client available to all tools registered inside `createServer`.
17
+
18
+ ## Prerequisites
19
+
20
+ Before using this generator, ensure you have:
21
+
22
+ 1. A <Link path="guides/ts-mcp-server">`ts#mcp-server`</Link> project
23
+ 2. A <Link path="guides/ts-rdb">`ts#rdb`</Link> project
24
+
25
+ ## Usage
26
+
27
+ ### Run the Generator
28
+
29
+ <RunGenerator generator="connection" />
30
+
31
+ Select your MCP server project as the source and your relational database project as the target. If the project contains multiple MCP server components, specify `sourceComponent` to disambiguate.
32
+
33
+ ### Options
34
+
35
+ <GeneratorParameters generator="connection" />
36
+
37
+ ## Generator Output
38
+
39
+ The generator modifies two files in your MCP server's source directory:
40
+
41
+ <FileTree>
42
+
43
+ - packages/my-service/src/my-mcp
44
+ - server.ts Prisma client fetched and available to all tools registered inside `createServer`
45
+ - Dockerfile RDS CA bundle installed for SSL connections to Aurora
46
+
47
+ </FileTree>
48
+
49
+ Additionally, the `<mcp-server-name>-serve-local` target is updated to depend on the database's `serve-local` target.
50
+
51
+ ## How It Works
52
+
53
+ The Prisma client is fetched inside `createServer` and available to all tools and resources registered there:
54
+
55
+ ```ts title="packages/my-service/src/my-mcp/server.ts" {1,4}
56
+ import { getPrisma as getMyDb } from ':my-scope/my-db';
57
+
58
+ export const createServer = async () => {
59
+ const myDb = await getMyDb();
60
+ const server = new McpServer({ name: 'my-service', version: '1.0.0' });
61
+ // register tools/resources that use myDb
62
+ return server;
63
+ };
64
+ ```
65
+
66
+ ## Multiple Databases
67
+
68
+ Running the generator again with a different target adds the second database alongside the first. Both are fetched inside `createServer`:
69
+
70
+ ```ts title="packages/my-service/src/my-mcp/server.ts" {2,3}
71
+ export const createServer = async () => {
72
+ const postgresDb = await getPostgresDb();
73
+ const mysqlDb = await getMysqlDb();
74
+ const server = new McpServer({ ... });
75
+ // register tools using both clients
76
+ return server;
77
+ };
78
+ ```
79
+
80
+ ## Infrastructure
81
+
82
+ The generated MCP server construct implements `IGrantable` and `IConnectable`, so you can grant network and IAM access to the database directly on the construct.
83
+
84
+ <Infrastructure>
85
+ <Fragment slot="cdk">
86
+
87
+ ```ts title="packages/infra/src/stacks/application-stack.ts"
88
+ import { MyDatabase } from ':my-scope/common-constructs';
89
+
90
+ const db = new MyDatabase(this, 'Db', { vpc, ... });
91
+ const myMcpServer = new MyMcpServer(this, 'MyMcpServer', { vpc, ... });
92
+
93
+ db.allowDefaultPortFrom(myMcpServer);
94
+ db.grantConnect(myMcpServer);
95
+ ```
96
+
97
+ `allowDefaultPortFrom` opens the security group rule so the MCP server runtime can reach the database port. `grantConnect` grants IAM `rds-db:connect` permission to the server's execution role.
98
+
99
+ </Fragment>
100
+ <Fragment slot="terraform">
101
+
102
+ Pass the database module outputs into your MCP server module so it can reach the database and read its runtime configuration:
103
+
104
+ ```hcl title="packages/infra/src/main.tf"
105
+ module "my_database" {
106
+ source = "../../common/terraform/src/app/dbs/my-database"
107
+ vpc_id = module.vpc.vpc_id
108
+ database_subnet_ids = module.vpc.private_isolated_subnet_ids
109
+ }
110
+
111
+ module "my_mcp_server" {
112
+ source = "../../common/terraform/src/app/mcp-servers/my-mcp-server"
113
+
114
+ appconfig_application_id = module.my_database.appconfig_application_id
115
+ database_cluster_resource_id = module.my_database.cluster_resource_id
116
+ database_runtime_user = module.my_database.database_runtime_user
117
+ database_security_group_id = module.my_database.security_group_id
118
+ database_port = module.my_database.cluster_port
119
+ }
120
+ ```
121
+
122
+ Ensure the MCP server's execution role has `rds-db:connect` permission and that its security group can reach the database security group on the database port.
123
+
124
+ </Fragment>
125
+ </Infrastructure>
126
+
127
+ ### SSL Requirements When Connecting Without RDS Proxy
128
+
129
+ <Snippet name="connection/mcp-server-rdb-ssl-requirements" parentHeading="SSL Requirements When Connecting Without RDS Proxy" />
130
+
131
+ ## Local Development
132
+
133
+ <NxCommands commands={["<mcp-server-name>-serve-local <project-name>"]} />
134
+
135
+ This starts the MCP server and all connected databases. The `SERVE_LOCAL=true` environment variable causes each Prisma client to connect to its local Docker database instead of Aurora.
@@ -0,0 +1,126 @@
1
+ ---
2
+ title: Connection
3
+ description: Reference documentation for connections
4
+ ---
5
+ import Astro from '@astrojs/react';
6
+ import { CardGrid, LinkButton } from '@astrojs/starlight/components';
7
+ import Link from '@components/link.astro';
8
+ import ConnectionCard from '@components/connection-card.astro';
9
+
10
+ This generator is used to connect projects together, such as websites calling APIs. Simply select the source project (for example the project that will call your API) and target project (for example your API project), and this generator will handle integrating the two.
11
+
12
+ ### Supported Connections
13
+
14
+ The Connection generator supports the following connections:
15
+
16
+ <CardGrid>
17
+ <ConnectionCard
18
+ title="React to tRPC"
19
+ description="Call a tRPC API from a React website"
20
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/react-trpc`}
21
+ source="react"
22
+ target="trpc"
23
+ />
24
+ <ConnectionCard
25
+ title="React to FastAPI"
26
+ description="Call a Python FastAPI from a React website"
27
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/react-fastapi`}
28
+ source="react"
29
+ target="fastapi"
30
+ />
31
+ <ConnectionCard
32
+ title="React to Smithy API"
33
+ description="Call a Smithy API from a React website"
34
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/react-smithy`}
35
+ source="react"
36
+ target="smithy"
37
+ />
38
+ <ConnectionCard
39
+ title="React to Python Agent"
40
+ description="Call a Python Agent from a React website"
41
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/react-py-agent`}
42
+ source="react"
43
+ target="strands"
44
+ targetBadge="python"
45
+ />
46
+ <ConnectionCard
47
+ title="React to TypeScript Agent"
48
+ description="Call a TypeScript Agent from a React website"
49
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/react-ts-agent`}
50
+ source="react"
51
+ target="strands"
52
+ targetBadge="typescript"
53
+ />
54
+ <ConnectionCard
55
+ title="React to AG-UI Agent"
56
+ description="Call an Agent exposing the AG-UI protocol from a React website via CopilotKit"
57
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/react-agui`}
58
+ source="react"
59
+ target="copilotkit"
60
+ />
61
+ <ConnectionCard
62
+ title="Python Agent to MCP"
63
+ description="Connect a Python Agent to an MCP server"
64
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/py-agent-mcp`}
65
+ source="strands"
66
+ sourceBadge="python"
67
+ target="mcp"
68
+ />
69
+ <ConnectionCard
70
+ title="TypeScript Agent to MCP"
71
+ description="Connect a TypeScript Agent to an MCP server"
72
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/ts-agent-mcp`}
73
+ source="strands"
74
+ sourceBadge="typescript"
75
+ target="mcp"
76
+ />
77
+ <ConnectionCard
78
+ title="Python Agent to A2A Agent"
79
+ description="Connect a Python Agent to a remote A2A agent"
80
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/py-agent-a2a`}
81
+ source="strands"
82
+ sourceBadge="python"
83
+ target="a2a"
84
+ />
85
+ <ConnectionCard
86
+ title="TypeScript Agent to A2A Agent"
87
+ description="Connect a TypeScript Agent to a remote A2A agent"
88
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/ts-agent-a2a`}
89
+ source="strands"
90
+ sourceBadge="typescript"
91
+ target="a2a"
92
+ />
93
+ <ConnectionCard
94
+ title="tRPC API to Relational Database"
95
+ description="Connect a tRPC API to an Aurora relational database"
96
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/trpc-rdb`}
97
+ source="trpc"
98
+ target="aurora"
99
+ />
100
+ <ConnectionCard
101
+ title="Smithy API to Relational Database"
102
+ description="Connect a Smithy API to an Aurora relational database"
103
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/smithy-rdb`}
104
+ source="smithy"
105
+ target="aurora"
106
+ />
107
+ <ConnectionCard
108
+ title="TypeScript Agent to Relational Database"
109
+ description="Connect a TypeScript Agent to an Aurora relational database"
110
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/ts-agent-rdb`}
111
+ source="strands"
112
+ sourceBadge="typescript"
113
+ target="aurora"
114
+ />
115
+ <ConnectionCard
116
+ title="MCP Server to Relational Database"
117
+ description="Connect a TypeScript MCP Server to an Aurora relational database"
118
+ href={`/nx-plugin-for-aws/${Astro.currentLocale || 'en'}/guides/connection/ts-mcp-server-rdb`}
119
+ source="mcp"
120
+ target="aurora"
121
+ />
122
+ </CardGrid>
123
+
124
+ :::note[Runtime Configuration]
125
+ The connection generator makes use of <Link path="guides/runtime-config">Runtime Configuration</Link> to pass deploy-time values (such as API URLs, Cognito settings, and agent runtime ARNs) between generated projects and components at runtime so they can discover and connect to one another.
126
+ :::
@@ -0,0 +1,403 @@
1
+ ---
2
+ title: Docker Bundling
3
+ description: Build and deploy Docker images for TypeScript and Python projects in an Nx Plugin for AWS workspace.
4
+ ---
5
+
6
+ import { FileTree, Tabs, TabItem } from '@astrojs/starlight/components';
7
+ import NxCommands from '@components/nx-commands.astro';
8
+ import Link from '@components/link.astro';
9
+ import Infrastructure from '@components/infrastructure.astro';
10
+
11
+ Several generators (such as <Link path="/guides/ts-agent">`ts#agent`</Link> and <Link path="/guides/py-agent">`py#agent`</Link>) produce a Docker image that is pushed to Amazon ECR and consumed by AWS infrastructure. This guide describes the pattern they follow so that you can apply it to other use cases — for example, running a <Link path="/guides/fastapi">`py#fast-api`</Link> project on Amazon ECS, or deploying a containerised Express server.
12
+
13
+ :::tip[Docker or Finch]
14
+ The container engine used to build images is chosen at workspace creation time via the `--containerEngine` flag (`docker`, `finch`, or `infer` — the default — which auto-detects what's installed). [Finch](https://runfinch.com/) is an open-source, drop-in alternative to Docker. The selection is recorded in `aws-nx-plugin.config.mts` and applied to every generator that emits container build commands. CDK image asset builds honour the choice via the `CDK_DOCKER` environment variable.
15
+ :::
16
+
17
+ ## The Pattern
18
+
19
+ ```d2
20
+ direction: right
21
+
22
+ src: src/
23
+ dockerfile: Dockerfile {
24
+ shape: document
25
+ }
26
+ bundle: "bundle target\nRolldown / uv"
27
+ ctx: "dist/.../bundle/\n(build context)" {
28
+ shape: page
29
+ }
30
+
31
+ src -> bundle -> ctx
32
+ dockerfile -> ctx
33
+ ```
34
+
35
+ The recommended pattern has three pieces:
36
+
37
+ 1. **A `bundle` target** on your project which produces a self-contained directory of runtime artifacts. For TypeScript this is a tree-shaken, single-file JavaScript bundle produced by [Rolldown](https://rolldown.rs/); for Python this is a `requirements.txt` and installed dependencies produced by [uv](https://docs.astral.sh/uv/).
38
+ 2. **A minimal `Dockerfile`** which simply `COPY`s the bundle output into a base image. Because bundling already handled tree-shaking and dependency installation, the `Dockerfile` does not need to run `npm install` or `uv sync`.
39
+ 3. **A `docker` target** which copies the `Dockerfile` alongside the bundle output (so that the Docker build context only contains files needed at runtime), then runs `docker build`.
40
+
41
+ The Docker build context is written to your project's `dist` folder. Your infrastructure as code (CDK or Terraform) then points at that directory to push the image to ECR.
42
+
43
+ :::tip[Why bundle outside the Dockerfile?]
44
+ Keeping the bundle step in Nx (rather than inside the `Dockerfile`) means:
45
+
46
+ - Nx can **cache** the bundle target, so repeated builds are fast.
47
+ - The `Dockerfile` does not need access to your monorepo, private registries, or build-time secrets.
48
+ - The image layer is tiny — a single `COPY` of already-built artifacts, with no transitive `node_modules` or build toolchain.
49
+ :::
50
+
51
+ ## TypeScript
52
+
53
+ ### Bundle Target
54
+
55
+ Configure a `bundle` target that invokes Rolldown. If you are starting from a <Link path="/guides/typescript-project">`ts#project`</Link>, add the following to your `project.json`:
56
+
57
+ ```json
58
+ {
59
+ "targets": {
60
+ "bundle": {
61
+ "cache": true,
62
+ "executor": "nx:run-commands",
63
+ "outputs": ["{workspaceRoot}/dist/{projectRoot}/bundle"],
64
+ "options": {
65
+ "command": "rolldown -c rolldown.config.ts",
66
+ "cwd": "{projectRoot}"
67
+ },
68
+ "dependsOn": ["compile"]
69
+ }
70
+ }
71
+ }
72
+ ```
73
+
74
+ And a `rolldown.config.ts` at the root of your project:
75
+
76
+ ```ts
77
+ // rolldown.config.ts
78
+ import { defineConfig } from 'rolldown';
79
+
80
+ export default defineConfig([
81
+ {
82
+ tsconfig: 'tsconfig.lib.json',
83
+ input: 'src/index.ts',
84
+ output: {
85
+ file: '../../dist/packages/my-project/bundle/index.js',
86
+ format: 'cjs',
87
+ inlineDynamicImports: true,
88
+ },
89
+ platform: 'node',
90
+ },
91
+ ]);
92
+ ```
93
+
94
+ Run the bundle target to produce `dist/packages/my-project/bundle/index.js`:
95
+
96
+ <NxCommands commands={['bundle my-project']} />
97
+
98
+ :::tip[Non-bundleable dependencies]
99
+ Some npm packages cannot be bundled because they rely on dynamic `require`, native bindings, or runtime file-path resolution. Add them to the `external` array in `rolldown.config.ts` so they are left as runtime `require()` calls, and install them inside the `Dockerfile` instead (see below):
100
+
101
+ ```ts
102
+ {
103
+ // ...
104
+ external: ['@aws/aws-distro-opentelemetry-node-autoinstrumentation'],
105
+ }
106
+ ```
107
+ :::
108
+
109
+ ### Dockerfile
110
+
111
+ Create a `Dockerfile` in your project source directory. The file does nothing more than `COPY` the bundle into a Node base image, plus `npm install` any `external` packages that could not be bundled. Place the `RUN npm install` step **before** the `COPY`, so Docker can cache the installed `node_modules` layer and only re-run it when the dependency list actually changes:
112
+
113
+ ```dockerfile
114
+ FROM public.ecr.aws/docker/library/node:lts
115
+
116
+ WORKDIR /app
117
+
118
+ # Install packages that cannot be bundled (declared as "external" in rolldown.config.ts).
119
+ # Kept above the COPY so this layer is cached and only invalidated when the install list changes.
120
+ RUN npm install @aws/aws-distro-opentelemetry-node-autoinstrumentation@0.10.0
121
+
122
+ # Copy bundled application
123
+ COPY index.js /app
124
+
125
+ EXPOSE 8080
126
+
127
+ CMD ["node", "index.js"]
128
+ ```
129
+
130
+ :::tip[Pin your dependencies]
131
+ Pin every dependency installed inside the `Dockerfile` to an exact version (as above) — otherwise `npm install` will silently pick up a newer release the next time you build, producing images that behave differently depending on when they were built.
132
+ :::
133
+
134
+ ### Docker Target
135
+
136
+ Add a `docker` target which:
137
+
138
+ 1. Copies the `Dockerfile` into the bundle output directory (so the build context contains only the bundle + `Dockerfile`), and
139
+ 2. Runs `docker build` (optional for CDK — see below).
140
+
141
+ ```json
142
+ {
143
+ "targets": {
144
+ "docker": {
145
+ "cache": true,
146
+ "executor": "nx:run-commands",
147
+ "options": {
148
+ "commands": [
149
+ "ncp packages/my-project/src/Dockerfile dist/packages/my-project/bundle/Dockerfile",
150
+ "docker build --platform linux/arm64 -t my-scope-my-project:latest dist/packages/my-project/bundle"
151
+ ],
152
+ "parallel": false
153
+ },
154
+ "dependsOn": ["bundle"]
155
+ }
156
+ }
157
+ }
158
+ ```
159
+
160
+ :::tip[Cross-platform file copy]
161
+ The `ncp` package provides a cross-platform file/directory copy command, avoiding `cp` (unavailable on Windows). Install it at the root of your workspace with `pnpm add -D -w ncp`.
162
+ :::
163
+
164
+ Running this target produces a local image tagged `my-scope-my-project:latest`, built from the minimal context at `dist/packages/my-project/bundle/`:
165
+
166
+ <NxCommands commands={['docker my-project']} />
167
+
168
+ :::note[CDK builds the image itself]
169
+ If you are only deploying with CDK, the `docker build` command above is optional — CDK's `DockerImageAsset` (shown under [Infrastructure](#infrastructure)) will build the image for you at synth time. You still need to copy the `Dockerfile` into the build-context directory so CDK can find it. The generators keep the local `docker build` step to give you a quick way to smoke-test the image with `docker run`.
170
+
171
+ For Terraform, the `docker build` step is required — the `null_resource` pattern below pushes a locally-tagged image.
172
+ :::
173
+
174
+ ## Python
175
+
176
+ ### Bundle Target
177
+
178
+ Configure a `bundle` target that uses `uv` to export and install dependencies for your target platform. The <Link path="/guides/python-project">`py#project`</Link> generator and the <Link path="/guides/python-lambda-function">`py#lambda-function`</Link> generator both configure this for you. The target configuration looks like:
179
+
180
+ ```json
181
+ {
182
+ "targets": {
183
+ "bundle-arm": {
184
+ "cache": true,
185
+ "executor": "nx:run-commands",
186
+ "outputs": ["{workspaceRoot}/dist/{projectRoot}/bundle-arm"],
187
+ "options": {
188
+ "commands": [
189
+ "uv export --frozen --no-dev --no-editable --project {projectRoot} --package my_project -o dist/{projectRoot}/bundle-arm/requirements.txt",
190
+ "uv pip install -n --no-deps --no-installer-metadata --no-compile-bytecode --python-platform aarch64-manylinux_2_28 --target dist/{projectRoot}/bundle-arm -r dist/{projectRoot}/bundle-arm/requirements.txt"
191
+ ],
192
+ "parallel": false
193
+ },
194
+ "dependsOn": ["compile"]
195
+ }
196
+ }
197
+ }
198
+ ```
199
+
200
+ :::tip[Target architecture]
201
+ Change `--python-platform` to `x86_64-manylinux_2_28` if your Docker image will run on x86_64.
202
+ :::
203
+
204
+ Running `nx bundle my-project` produces `dist/packages/my-project/bundle-arm/` containing your project's source, its dependencies, and a `requirements.txt` — everything the image needs at runtime.
205
+
206
+ ### Dockerfile
207
+
208
+ The `Dockerfile` simply copies the bundle into a Python base image. Because `uv` already installed all dependencies into the bundle directory, you do not need to run `pip install` inside the image:
209
+
210
+ ```dockerfile
211
+ FROM public.ecr.aws/docker/library/python:3.14-slim
212
+
213
+ WORKDIR /app
214
+
215
+ # Copy bundled package (source + installed dependencies)
216
+ COPY . /app
217
+
218
+ EXPOSE 8080
219
+
220
+ ENV PYTHONPATH=/app
221
+ ENV PATH="/app/bin:${PATH}"
222
+
223
+ CMD ["python", "-m", "my_project.main"]
224
+ ```
225
+
226
+ ### Docker Target
227
+
228
+ Add a `docker` target which copies the `Dockerfile` into the bundle output directory, then runs `docker build`:
229
+
230
+ ```json
231
+ {
232
+ "targets": {
233
+ "docker": {
234
+ "cache": true,
235
+ "executor": "nx:run-commands",
236
+ "options": {
237
+ "commands": [
238
+ "rimraf dist/packages/my-project/docker",
239
+ "make-dir dist/packages/my-project/docker",
240
+ "ncp dist/packages/my-project/bundle-arm dist/packages/my-project/docker",
241
+ "ncp packages/my-project/src/Dockerfile dist/packages/my-project/docker/Dockerfile",
242
+ "docker build --platform linux/arm64 -t my-scope-my-project:latest dist/packages/my-project/docker"
243
+ ],
244
+ "parallel": false
245
+ },
246
+ "dependsOn": ["bundle-arm"]
247
+ }
248
+ }
249
+ }
250
+ ```
251
+
252
+ This clears the output directory, then copies both the bundle contents and the `Dockerfile` into `dist/.../docker`, which becomes the Docker build context.
253
+
254
+ <NxCommands commands={['docker my-project']} />
255
+
256
+ ## Infrastructure
257
+
258
+ Wiring the resulting build-context directory to infrastructure as code is the same for both TypeScript and Python — only the path to the build-context directory differs (`dist/packages/my-project/bundle` for TypeScript, `dist/packages/my-project/docker` for Python).
259
+
260
+ <Infrastructure>
261
+ <Fragment slot="cdk">
262
+ Use CDK's [`DockerImageAsset`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecr_assets.DockerImageAsset.html) pointed at the build-context directory. CDK will build the image and publish it to the CDK asset ECR repository at deploy time:
263
+
264
+ ```d2
265
+ direction: right
266
+
267
+ app: Application {
268
+ bundle: "bundle target\nRolldown / uv"
269
+ dockerfile: Dockerfile {
270
+ shape: document
271
+ }
272
+ ctx: "dist/.../bundle/" {
273
+ shape: page
274
+ }
275
+ bundle -> ctx
276
+ dockerfile -> ctx
277
+ }
278
+
279
+ infra: Infrastructure {
280
+ asset: "DockerImageAsset\ndirectory: dist/.../bundle"
281
+ }
282
+
283
+ ecr: "CDK asset ECR" {
284
+ shape: cylinder
285
+ }
286
+
287
+ infra.asset -> app.ctx: references
288
+ infra.asset -> ecr: cdk deploy\nbuilds + pushes
289
+ ```
290
+
291
+
292
+ ```ts
293
+ import { DockerImageAsset, Platform } from 'aws-cdk-lib/aws-ecr-assets';
294
+ import { findWorkspaceRoot } from ':my-scope/common-constructs';
295
+ import * as path from 'path';
296
+ import * as url from 'url';
297
+
298
+ const image = new DockerImageAsset(this, 'MyImage', {
299
+ directory: path.join(
300
+ // Resolve from the compiled construct location to the workspace root
301
+ findWorkspaceRoot(url.fileURLToPath(new URL(import.meta.url))),
302
+ 'dist/packages/my-project/bundle',
303
+ ),
304
+ platform: Platform.LINUX_ARM64,
305
+ });
306
+ ```
307
+
308
+ The `findWorkspaceRoot` helper is generated by the <Link path="/guides/typescript-infrastructure">`ts#infra`</Link> generator and exported from `:my-scope/common-constructs`. If you are not using shared constructs, you can hardcode the path to the `dist` directory relative to where `cdk` is invoked from — typically the workspace root — and omit the `findWorkspaceRoot` call entirely.
309
+
310
+ :::note[Running bundle before synth]
311
+ CDK does not run the `bundle`/`docker` targets automatically — you must run `nx build my-project` (or wire the deploy target to depend on `build`) before `cdk deploy`. The generators that use this pattern declare `docker` and `bundle` as dependencies of `build` so this happens transparently.
312
+ :::
313
+
314
+ Use the `DockerImageAsset` with any AWS construct that accepts a container image, for example `aws_ecs.ContainerImage.fromDockerImageAsset(image)`.
315
+ </Fragment>
316
+ <Fragment slot="terraform">
317
+ Terraform's AWS provider does not have a first-class "build and push a Docker image" resource. The pattern used by the generators is:
318
+
319
+ 1. The project's `build` target runs `docker build`, producing a local image tagged `my-scope-my-project:latest`.
320
+ 2. An `aws_ecr_repository` to hold the image.
321
+ 3. A `null_resource` with a `local-exec` provisioner that authenticates to ECR, re-tags the locally-built image, and pushes it.
322
+ 4. The downstream resource (e.g. `aws_ecs_task_definition`) references `"${aws_ecr_repository.repo.repository_url}:latest"`.
323
+
324
+ ```d2
325
+ direction: down
326
+
327
+ app: Application {
328
+ bundle: "bundle target\nRolldown / uv"
329
+ dockerfile: Dockerfile {
330
+ shape: document
331
+ }
332
+ ctx: "dist/.../bundle/" {
333
+ shape: page
334
+ }
335
+ build: "docker target\ndocker build"
336
+ img: "local image\nmy-scope-my-project:latest" {
337
+ shape: cylinder
338
+ }
339
+
340
+ bundle -> ctx
341
+ dockerfile -> ctx
342
+ ctx -> build -> img
343
+ }
344
+
345
+ infra: Infrastructure {
346
+ direction: right
347
+ publish: "null_resource\nlocal-exec: docker push"
348
+ repo: aws_ecr_repository
349
+ publish -> repo: tag + push
350
+ }
351
+
352
+ ecr: "Amazon ECR" {
353
+ shape: cylinder
354
+ }
355
+
356
+ infra.publish -> app.img: reads local image
357
+ infra.repo -> ecr
358
+ ```
359
+
360
+
361
+ ```hcl
362
+ resource "aws_ecr_repository" "repo" {
363
+ name = "my-project-repository"
364
+ image_tag_mutability = "MUTABLE"
365
+ force_delete = true
366
+ }
367
+
368
+ # Invalidate the push whenever the locally-built image digest changes
369
+ data "external" "docker_digest" {
370
+ program = ["sh", "-c", "echo '{\"digest\":\"'$(docker inspect my-scope-my-project:latest --format '{{.Id}}')'\"}'"]
371
+ }
372
+
373
+ resource "null_resource" "docker_publish" {
374
+ triggers = {
375
+ docker_digest = data.external.docker_digest.result.digest
376
+ repository_url = aws_ecr_repository.repo.repository_url
377
+ }
378
+
379
+ provisioner "local-exec" {
380
+ command = <<-EOT
381
+ aws ecr get-login-password --region ${data.aws_region.current.id} \
382
+ | docker login --username AWS --password-stdin ${self.triggers.repository_url}
383
+ docker tag my-scope-my-project:latest ${self.triggers.repository_url}:latest
384
+ docker push ${self.triggers.repository_url}:latest
385
+ EOT
386
+ }
387
+ }
388
+ ```
389
+
390
+ The `data.external.docker_digest` block ensures the `null_resource` re-runs whenever the local image hash changes, triggering a new push on every meaningful code change.
391
+
392
+ :::note[Running bundle before apply]
393
+ `nx apply <project>` requires the image tag `my-scope-my-project:latest` to already exist locally. Run `nx build my-project` (or `nx docker my-project`) before `nx apply <project>`.
394
+ :::
395
+ </Fragment>
396
+ </Infrastructure>
397
+
398
+ ## Further Reading
399
+
400
+ - <Link path="/guides/ts-agent">`ts#agent` generator</Link> — a complete example of this pattern for a TypeScript agent deployed to Bedrock AgentCore Runtime.
401
+ - <Link path="/guides/py-agent">`py#agent` generator</Link> — the equivalent for Python.
402
+ - [Rolldown documentation](https://rolldown.rs/) — configuration reference for the TypeScript bundler.
403
+ - [`uv` documentation](https://docs.astral.sh/uv/) — reference for Python dependency export and install.