Skip to content

feat: add customize callback to createApp, remove autoStart#280

Draft
MarioCadenas wants to merge 4 commits intomainfrom
feat/customize-callback
Draft

feat: add customize callback to createApp, remove autoStart#280
MarioCadenas wants to merge 4 commits intomainfrom
feat/customize-callback

Conversation

@MarioCadenas
Copy link
Copy Markdown
Collaborator

@MarioCadenas MarioCadenas commented Apr 16, 2026

Summary

  • Adds an onPluginsReady lifecycle hook to createApp that runs after plugin setup but before the server starts, replacing the autoStart: false + .extend() + .start() ceremony
  • Server start is now orchestrated by createApp (looks up "server" plugin by name), making autoStart and manual start() unnecessary
  • Removes autoStart from public API (ServerConfig, DEFAULT_CONFIG, manifest) and start() from server exports
  • Adds appkit codemod customize-callback CLI command to auto-migrate existing apps
  • Adds runtime detection that throws helpful errors directing users to the codemod

Before / After

Before:

const appkit = await createApp({
  plugins: [server({ autoStart: false }), analytics({})],
});
appkit.server.extend((app) => {
  app.get("/custom", (_req, res) => res.json({ ok: true }));
});
await appkit.server.start();

After:

await createApp({
  plugins: [server(), analytics({})],
  onPluginsReady(appkit) {
    appkit.server.extend((app) => {
      app.get("/custom", (_req, res) => res.json({ ok: true }));
    });
  },
});

Migration

npx appkit codemod customize-callback --write

Auto-detects server entry files and rewrites both .then() chain and await + imperative patterns. Dry-run by default (omit --write to preview).

Test plan

  • All existing tests updated and passing (1569/1569)
  • New integration tests for onPluginsReady (sync, async, without server plugin)
  • Codemod tests: Pattern A, Pattern B, bail-out, idempotency, autoStart stripping
  • Runtime detection tests: constructor throws on autoStart, exports().start() throws
  • Typecheck passes
  • Build passes
  • Biome lint passes on changed files

Replace the post-await extend/start ceremony with a declarative
`customize` callback on createApp config. The callback runs after
plugin setup but before the server starts, giving access to the
full appkit handle for registering custom routes or async setup.

- Add `customize` option to createApp config
- Server start is now orchestrated by createApp (lookup by name)
- Remove `autoStart` from public API, ServerConfig, and manifest
- Remove `start()` from server plugin exports
- Remove autoStart guards from extend() and getServer()
- Remove ServerError.autoStartConflict()
- Migrate dev-playground, template, and all tests

Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
@MarioCadenas MarioCadenas force-pushed the feat/customize-callback branch from d49f16d to 33e0b86 Compare April 16, 2026 10:43
@atilafassina
Copy link
Copy Markdown
Contributor

I think this is a step in the right direction and we should have this ASAP.
We did a quick search on other server frameworks out there and owning the lifecycle of plugins simplifies things a lot in orchestrating functionality and avoiding race conditions. Removing the autoStart config is just a user-facing bonus of having a more reliable architecture beneath it.

That being said, as we talked on Slack (just surfacing this here), the API name could change. customize doesn't really translates to the user only the intent, not what it's doing (and more importantly when), makes it less intuitive and discoverable. customize should be split in pre() and post() hooks, running respectively before and after plugin instantiation.

The use case we need to cover immediately is pre(), so I think just renaming this here and shipping this incrementally would be great already, we cross the post() bridge when we get there perhaps - who knows, maybe we need more hooks in the future as our typegen/compiler story evolves.

… detection

Rename the lifecycle hook from `customize` to `onPluginsReady` to
clearly communicate when it fires (after plugins are ready, before
server starts).

Add `appkit codemod customize-callback` CLI command that auto-migrates
old autoStart/extend/start patterns to the new onPluginsReady callback.
Supports both .then() chain (Pattern A) and await + imperative
(Pattern B, with bail-out for complex cases).

Add runtime detection that throws helpful errors when users pass
autoStart to server() or call server.start() after upgrading,
directing them to run the codemod.

Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
The test fixture .ts files import @databricks/appkit which doesn't
exist in the shared package, causing tsc to fail in CI. Exclude
the fixtures directory from the shared tsconfig.

Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Remove the codemod CLI from this PR to keep the review focused
on the core lifecycle change. The codemod will land as a follow-up
with bug fixes from review.

Runtime detection (constructor autoStart throw + exports().start()
trap) stays since it's part of the migration story.

Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
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.

2 participants