Skip to content

Add --external-database flag for externally-managed databases - #173

Open
blsmth wants to merge 2 commits into
mainfrom
issue-146-external-database
Open

Add --external-database flag for externally-managed databases#173
blsmth wants to merge 2 commits into
mainfrom
issue-146-external-database

Conversation

@blsmth

@blsmth blsmth commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Closes #146.

Adds --external-database <postgres|mysql> to apppack create app, which sets a new ExternalDatabaseEngine CloudFormation parameter so db shell/db dump/db load can target an externally-managed database (Neon, Crunchy, etc.) reachable via the app's DATABASE_URL config variable. Also adds a matching interactive prompt in AskForDatabase (for apppack modify app), client-side validation (mutually exclusive with --addon-database/--addon-database-name, engine must be postgres or mysql), and replaces the unhelpful "unknown database engine " error with a targeted message pointing users at either apppack modify app/--external-database or apppack create database.

Depends on the formations change (apppack-backend) landing and being released first — until formations emits dbutils.engine for externally-configured apps, setting this flag has no effect.

Caveat carried over from the spec: apppack db load's load-from-s3.sh script likely does a DROP/CREATE of the target database, which some managed providers (e.g. Neon) may not permit for the app's role. db shell and db dump are the confident wins here; db load may not reach full parity even after this lands.

Happy path (DBShellTaskInfo/DBDumpLocation/DBDumpLoadFamily, isPostgres in cmd/db.go) is unchanged.

Want a Test Plan section added, or is this concise enough as-is?

Registers ExternalDatabaseEngine as a CloudFormation parameter on
apppack create app (postgres|mysql), validates it is mutually
exclusive with --addon-database/--addon-database-name, and adds a
matching interactive prompt in AskForDatabase for apppack modify app.

Also replaces the unhelpful "unknown database engine " error (empty
engine) with a targeted message that checks for a DATABASE_URL config
variable and tells the user how to enable db utils or create a
database.
@ipmb

ipmb commented Aug 12, 2026 via email

Copy link
Copy Markdown
Member

ipmb reviewed #173 and pointed out the user should never have to type
the database engine -- it's inferable from the DATABASE_URL scheme.
Delete --external-database and both interactive prompts; SetInternalFields
now auto-detects the engine from the app's DATABASE_URL config variable
via SSM, for both `create app` and `modify app`.

A managed AppPack database and pipelines/review apps always force the
field back to "", so this is idempotent no matter how many times
`modify app` runs. Any SSM/parse failure is silent (the common case,
since `create app` runs before the app exists); an unrecognized scheme
still gets one warning line, since there's no longer a flag to fall
back on.

The formations-side CloudFormation parameter and condition are unchanged
-- every db-utils resource is still gated on DatabaseEnabled, and there
is no task definition to run for an external DB without it.
@blsmth

blsmth commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

Pushed an update that addresses your review: --external-database and both interactive prompts (enable? / which engine?) are gone. SetInternalFields now infers ExternalDatabaseEngine from the app's DATABASE_URL config variable (read from SSM), comparing only the URL scheme -- postgres/postgresql/pgsql/psql -> postgres, mysql/mysql2/mariadb -> mysql. This runs for both create app and modify app, so the resulting workflow is:

apppack create app ...
apppack config set DATABASE_URL=...
apppack modify app <name>   # picks up the engine automatically

A managed AppPack database (--addon-database/--addon-database-name) always wins and forces the field back to "", and pipelines/review apps are excluded, since the CloudFormation condition requires IsApp -- so detection is idempotent no matter how many times modify app runs.

On the "no CloudFormation changes" half of your comment: that part isn't achievable. Every db-utils resource (task definitions, execution/task roles, log group, S3 bucket) is gated behind DatabaseEnabled, and app.StartTask only ever does DescribeTaskDefinition -> RunTask -- there's no task-definition family to run against for an external DB without the formations change. That half of the PR is unchanged.

One tradeoff worth flagging: since there's no flag anymore, there's also no escape hatch for a DATABASE_URL with a scheme we don't recognize -- we print one warning and leave db shell/db dump disabled rather than failing the deploy. Happy to add --external-database back as a hidden override for that case if you'd rather have one. Let me know.

@ipmb

ipmb commented Aug 19, 2026 via email

Copy link
Copy Markdown
Member

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow DB commands against external databases

2 participants