Aqueduct #

Aqueduct is no longer actively developed. The last packages were released for Dart 2.x and aren’t compatible with Dart 3.x. If you’re starting a new project, use Conduit — the actively maintained official fork of Aqueduct with nearly identical APIs. This article remains relevant as a reference for understanding existing Aqueduct codebases and as a migration guide to Conduit.

Aqueduct was a highly influential Dart web server framework — introducing Dart-based ORM concepts, integrated OAuth2 authentication, and database migrations to the Dart ecosystem long before alternatives existed. Many tutorials, articles, and codebases on the internet still use Aqueduct. Understanding Aqueduct — especially its differences from Conduit — matters if you work with existing code or read old documentation.

A Brief History #

flowchart LR
    A["Aqueduct\n2016-2021\nActively developed\nPopular in Dart 2.x"] -->|Not Dart 3 compatible\nMaintainer stopped| B["Abandoned\n2021+"]
    B -->|Community fork\nActively developed| C["Conduit\n2021-present\nDart 3 compatible\nNearly identical API"]
AspectAqueductConduit
Status❌ Deprecated✅ Active
Dart 3 support❌ No✅ Yes
APIOriginalNearly identical
Packageaqueductconduit_core
CLIaqueductconduit
Migration from AqueductEasy (minimal changes)

Aqueduct Core Concepts Still Relevant #

Although Aqueduct is deprecated, its concepts live on in Conduit. Understanding Aqueduct means understanding Conduit’s foundation:

ApplicationChannel #

// Aqueduct — ApplicationChannel
import 'package:aqueduct/aqueduct.dart';

class TokoChannel extends ApplicationChannel {
  ManagedContext? context;

  @override
  Future prepare() async {
    final config = TokoConfig(options!.configurationFilePath!);
    final dataModel = ManagedDataModel.fromCurrentMirrorSystem();
    final psc = PostgreSQLPersistentStore(
      config.database.username,
      config.database.password,
      config.database.host,
      config.database.port,
      config.database.databaseName,
    );
    context = ManagedContext(dataModel, psc);
  }

  @override
  Controller get entryPoint {
    final router = Router();

    router
      .route('/produk/[:id]')
      .link(() => ProdukController(context!));

    return router;
  }
}
// Conduit — nearly identical, only the import differs
import 'package:conduit_core/conduit_core.dart';  // not aqueduct

class TokoChannel extends ApplicationChannel {
  // Exactly the same code as above
}

ResourceController #

// Aqueduct
import 'package:aqueduct/aqueduct.dart';

class ProdukController extends ResourceController {
  ProdukController(this.context);
  final ManagedContext context;

  @Operation.get()
  Future<Response> ambilSemua() async {
    final query = Query<Produk>(context);
    final hasil = await query.fetch();
    return Response.ok(hasil.map((p) => p.asMap()).toList());
  }

  @Operation.get('id')
  Future<Response> ambilSatu(@Bind.path('id') int id) async {
    final query = Query<Produk>(context)
      ..where((p) => p.id).equalTo(id);
    final produk = await query.fetchOne();
    if (produk == null) return Response.notFound();
    return Response.ok(produk.asMap());
  }
}
// Conduit — IDENTICAL, only the import differs
import 'package:conduit_core/conduit_core.dart';

class ProdukController extends ResourceController {
  // Exactly the same code
}

ManagedObject / ORM #

// Aqueduct — model definition
import 'package:aqueduct/aqueduct.dart';

class Produk extends ManagedObject<_Produk> implements _Produk {}

class _Produk {
  @primaryKey
  int? id;

  String? nama;
  double? harga;
  bool? aktif;
}
// Conduit — IDENTICAL
import 'package:conduit_core/conduit_core.dart';

class Produk extends ManagedObject<_Produk> implements _Produk {}
class _Produk {
  @primaryKey
  int? id;
  String? nama;
  double? harga;
  bool? aktif;
}

The Aqueduct → Conduit Migration Guide #

Migrating from Aqueduct to Conduit is relatively easy because the APIs are nearly identical. What needs to change:

1. pubspec.yaml #

# BEFORE (Aqueduct)
dependencies:
  aqueduct: ^4.0.0

dev_dependencies:
  aqueduct_test: ^4.0.0

# AFTER (Conduit)
dependencies:
  conduit_core: ^4.3.0
  conduit: ^4.3.0

dev_dependencies:
  conduit_test: ^4.3.0

2. Import Statements #

// BEFORE — all imports from aqueduct
import 'package:aqueduct/aqueduct.dart';
import 'package:aqueduct_test/aqueduct_test.dart';

// AFTER — switch to conduit
import 'package:conduit_core/conduit_core.dart';
import 'package:conduit_test/conduit_test.dart';

The fastest way to replace all imports in a project:

# Replace all aqueduct imports with conduit at once
find lib test -name "*.dart" -exec sed -i \
  "s/package:aqueduct\/aqueduct.dart/package:conduit_core\/conduit_core.dart/g" {} \;
find lib test -name "*.dart" -exec sed -i \
  "s/package:aqueduct_test\/aqueduct_test.dart/package:conduit_test\/conduit_test.dart/g" {} \;

3. CLI Commands #

# BEFORE (Aqueduct CLI)
aqueduct create nama_project
aqueduct serve
aqueduct db generate
aqueduct db upgrade
aqueduct db upgrade --dry-run

# AFTER (Conduit CLI)
conduit create nama_project
conduit serve
conduit db generate
conduit db upgrade
conduit db upgrade --dry-run

4. Incompatible API Changes #

Some small changes that might exist:

// Some class names changed (rarely)
// Aqueduct
import 'package:aqueduct/managed_auth.dart';
class Pengguna extends ManagedObject<_Pengguna>
    implements _Pengguna, ManagedAuthResourceOwner<_Pengguna> {}

// Conduit — different package name
import 'package:conduit_core/managed_auth.dart';
class Pengguna extends ManagedObject<_Pengguna>
    implements _Pengguna, ManagedAuthResourceOwner<_Pengguna> {}

Aqueduct Features Available in Conduit #

All of Aqueduct’s main features are available in Conduit:

✅ ResourceController with @Operation and @Bind
✅ ManagedObject ORM
✅ Type-safe query builder
✅ Automatic database migrations
✅ OAuth2 server (AuthServer, AuthController, Authorizer)
✅ ApplicationChannel
✅ Router with path parameters
✅ Testing with Agent/TestClient
✅ YAML configuration
✅ Multiple isolate support

Full Example: Aqueduct Code to Migrate #

Here’s a complete Aqueduct code example alongside its Conduit version:

// AQUEDUCT — main.dart
import 'package:aqueduct/aqueduct.dart';

Future main() async {
  final app = Application<TokoChannel>()
    ..options.configurationFilePath = 'config.yaml'
    ..options.port = 8888;

  await app.start(numberOfInstances: 3, consoleLogging: true);
}

// CONDUIT — main.dart (identical)
import 'package:conduit_core/conduit_core.dart';

Future main() async {
  final app = Application<TokoChannel>()
    ..options.configurationFilePath = 'config.yaml'
    ..options.port = 8888;

  await app.start(numberOfInstances: 3, consoleLogging: true);
}
// AQUEDUCT — query.dart
import 'package:aqueduct/aqueduct.dart';

Future<List<Produk>> ambilProdukMahal(ManagedContext context) async {
  return await (Query<Produk>(context)
    ..where((p) => p.harga).greaterThan(5000000)
    ..sortBy((p) => p.harga, QuerySortOrder.descending)
    ..fetchLimit = 10
  ).fetch();
}

// CONDUIT — query.dart (identical)
import 'package:conduit_core/conduit_core.dart';

Future<List<Produk>> ambilProdukMahal(ManagedContext context) async {
  return await (Query<Produk>(context)
    ..where((p) => p.harga).greaterThan(5000000)
    ..sortBy((p) => p.harga, QuerySortOrder.descending)
    ..fetchLimit = 10
  ).fetch();
}

When Is Old Aqueduct Documentation Still Relevant? #

Although Aqueduct is deprecated, there are situations where old Aqueduct documentation and tutorials are still useful:

STILL RELEVANT when:
  ✓ Maintaining an existing Aqueduct codebase that can't be migrated yet
  ✓ Reading old tutorials (2018-2021) — the concepts and patterns are the same
  ✓ Understanding Conduit's design decisions (Conduit inherits Aqueduct's philosophy)
  ✓ Learning from Aqueduct code examples — almost all of them apply to Conduit

NOT RELEVANT when:
  ✗ Starting a new project — use Conduit directly
  ✗ Following Aqueduct setup/installation — its CLI isn't Dart 3 compatible
  ✗ Using features specific to Aqueduct 3.x and below

Projects Still Using Aqueduct #

If you join a team with an old Aqueduct codebase, here’s the recommended approach:

1. If the project still runs on Dart 2.x — no need to migrate immediately
   Aqueduct works fine on Dart 2.x. Prioritize business features first.

2. If you need to upgrade to Dart 3.x — migration to Conduit is unavoidable
   Follow the migration guide above: replace imports, update pubspec.yaml, switch CLIs.

3. If the codebase is large and migration is risky — do it in one step
   Conduit and Aqueduct can't run side by side (package conflicts),
   so the migration must be done fully in a single step.

4. Test everything after migrating — there may be minor differences
   Especially around authentication behavior and some query edge cases.

Summary #

  • Aqueduct is deprecated and incompatible with Dart 3.x. For new projects, use Conduit — the actively maintained fork with a nearly identical API.
  • Migrating to Conduit is very easy — change imports from package:aqueduct/aqueduct.dart to package:conduit_core/conduit_core.dart, update pubspec.yaml, and replace the aqueduct CLI with conduit.
  • All Aqueduct concepts apply to ConduitApplicationChannel, ResourceController, ManagedObject, Query, AuthServer, Router are all available with the same names and APIs.
  • Old Aqueduct tutorials and articles are still useful for learning concepts — just swap the package name when following code examples.
  • The official Conduit documentation is at conduit.dart.io — more accurate and up-to-date than the old Aqueduct documentation.
  • Don’t install Aqueduct for new projects — the package isn’t Dart 3.x compatible and won’t receive bug fixes or security updates.
  • Existing Aqueduct codebases on Dart 2.x can be left as-is if there’s no urgent need to upgrade. Prioritize migration when you need Dart 3.x.
  • The aqueduct/managed_auth.dart import in Aqueduct becomes conduit_core/managed_auth.dart in Conduit — one of the most common errors during migration.

← Previous: Conduit   Next: Angel →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact