Skip to content

Migration Guide ​

Upgrade to v8.2 ​

Spry 8.2 changes the generated output layout, renames the Dart runtime target, and removes the wildcard-param alias that named catch-all routes used to receive.

The breaking changes are:

  • BuildTarget.dart is now BuildTarget.vm
  • generated Dart source moved from .spry/*.dart to .spry/src/*.dart
  • JS target entrypoints moved to deploy-facing filenames such as .spry/node/index.cjs and .spry/cloudflare/index.js
  • named catch-all routes no longer mirror their value onto event.params.wildcard

BuildTarget.dart -> BuildTarget.vm ​

Update your spry.config.dart target selection:

dart
// Before
defineSpryConfig(target: BuildTarget.dart);

// After
defineSpryConfig(target: BuildTarget.vm);

Generated output layout ​

If your deployment scripts or tooling execute generated files directly, update their paths:

  • .spry/main.dart -> .spry/src/main.dart
  • .spry/app.dart -> .spry/src/app.dart
  • .spry/hooks.dart -> .spry/src/hooks.dart
  • .spry/node/main.cjs -> .spry/node/index.cjs
  • .spry/bun/main.js -> .spry/bun/index.js
  • .spry/deno/main.js -> .spry/deno/index.js
  • .spry/cloudflare/cloudflare.mjs -> .spry/cloudflare/index.js

Spry 8.2 also adds native Dart build targets for direct deployment:

  • BuildTarget.exe
  • BuildTarget.aot
  • BuildTarget.jit
  • BuildTarget.kernel

Named catch-all params ​

Named catch-all route params no longer mirror their value onto event.params.wildcard. Read the remainder through the declared param name instead:

dart
// Before
final slug = event.params.wildcard;

// After
final slug = event.params.get('slug');

This applies to named catch-all filesystem routes such as routes/[...slug].dart, which continue to map to /**:slug.

What to verify after upgrading ​

  1. Update spry.config.dart to use BuildTarget.vm.
  2. Rebuild and re-check any deployment script, Dockerfile, or platform config that points at generated files under .spry/.
  3. Replace event.params.wildcard with the declared catch-all param name in route handlers.

Upgrade to v8 ​

If you are already on the file-routing model introduced in Spry 7, the move to v8 is small but not zero-cost.

The breaking changes are:

  • direct Request construction now follows the upstream Fetch-style init API
  • direct Response construction now follows the upstream Fetch-style init API
  • manual remainder route strings must use /** instead of /*

Direct Request construction ​

If you construct exported Request values yourself, switch to RequestInit:

dart
// Before
final request = Request(
  Uri.parse('https://example.com/users/42'),
  method: 'GET',
);

// After
final request = Request(
  Uri.parse('https://example.com/users/42'),
  RequestInit(method: HttpMethod.get),
);

Direct Response construction ​

If you build Response values directly, move status and headers into ResponseInit:

dart
// Before
return Response(
  status: 404,
  headers: {'content-type': 'application/json'},
  body: '{"error":"not_found"}',
);

// After
return Response(
  '{"error":"not_found"}',
  ResponseInit(
    status: 404,
    headers: {'content-type': 'application/json'},
  ),
);

Spry re-exports RequestInit and ResponseInit from package:spry/spry.dart and package:spry/app.dart, so most projects only need to update constructor calls.

Manual string routes ​

If you manually construct Spry, MiddlewareRoute, or ErrorRoute with string paths, change remainder matches from /* to /**:

dart
// Before
MiddlewareRoute(path: '/*', handler: requestLogger)
ErrorRoute(path: '/api/*', handler: apiError)

// After
MiddlewareRoute(path: '/**', handler: requestLogger)
ErrorRoute(path: '/api/**', handler: apiError)

Filesystem routes do not need a rename for this change. Spry will keep translating file names into the updated roux syntax for you.

What to verify after upgrading ​

  1. Re-run route matching tests if you use manual Spry(...) route maps.
  2. Rebuild any helper code that manually creates Request or Response objects.
  3. Check middleware and error scopes if they relied on /* remainder matching.

New routing syntax you can opt into ​

v8 also adds richer filesystem route syntax. These are additive features, not migration requirements:

  • regex params such as [id([0-9]+)]
  • optional params such as [[id]]
  • repeated params such as [...path+] and [[...path]]
  • embedded params such as post-[id].json
  • single-segment wildcards such as [_]

Upgrade from v6 to v7 ​

Spry 7 introduced a different center of gravity than older Spry guides. The framework moved to file routing, generated output, and runtime targets selected in config.

The headline shift ​

Old docs were centered on:

  • createSpry()
  • imperative route registration such as app.get(...)
  • group-based route composition
  • standalone server examples written by hand

Spry 7 is centered on:

  • routes/ as the source of truth
  • spry build and spry serve
  • defineSpryConfig(...)
  • a generated Spry(...) app and target-specific runtime entrypoint

What to replace in v7 ​

Imperative route registration ​

If you previously wrote app.get('/users/:id', handler);, move that logic into routes/users/[id].dart.

Route groups ​

If you relied on app.group(...), stop modeling route structure in code. Use folders plus _middleware.dart for scope-level behavior.

Manual server adapters ​

If your mental model was “I write the server wrapper myself”, move that concern into spry.config.dart and target selection.

Request helpers ​

Prefer the request-scoped Event object:

  • event.request
  • event.headers
  • event.params
  • event.locals
  • event.context

A migration path that usually works ​

  1. Move route logic into routes/.
  2. Add spry.config.dart.
  3. Replace shared wrappers with middleware/ and scoped _middleware.dart.
  4. Replace ad-hoc error translation with scoped _error.dart.
  5. Run dart run spry serve and inspect the generated output.

Released under the MIT License.