Dart Service Locator

Pub Version License Dart

A lightweight, fast dependency injection (DI) container for Dart and Flutter applications. Zero dependencies, O(1) performance, ~100 lines of code.

Quick Start

Installation

dependencies:
  dart_service_locator: ^2.0.0

Basic Usage

import 'package:dart_service_locator/dart_service_locator.dart';

// 1. Register
register<ApiService>(() => ApiService());

// 2. Locate
final api = locate<ApiService>();

// 3. Done!

Why dart_service_locator?

Feature dart_service_locator get_it
Pure Dart (no Flutter dependency)
Zero external dependencies
Lines of code ~100 ~2000+
Named instances
Disposal callbacks
Async factories
O(1) lookup
Learning curve Minimal Moderate

Perfect for:

  • Small to medium apps
  • Microservices & CLI tools
  • Projects wanting minimal overhead
  • Developers who prefer simplicity

Core Concepts

Registration Patterns

// Lazy singleton (created on first locate)
register<Logger>(() => ConsoleLogger());

// With disposal callback
register<Database>(
  () => Database(),
  dispose: (db) => db.close(),
);

// Named instances for multiple implementations
register<ApiClient>(() => ProdApi(), instanceName: 'prod');
register<ApiClient>(() => MockApi(), instanceName: 'mock');

Resolution Patterns

// Get singleton (same instance every time)
final logger = locate<Logger>();

// Create new instance each time
final fresh = create<Logger>();

// Named instance
final prod = locate<ApiClient>(instanceName: 'prod');

// Check before registering
if (!isRegistered<Logger>()) {
  register<Logger>(() => ConsoleLogger());
}

Dependency Chains

register<Logger>(() => ConsoleLogger());
register<Database>(() => Database(locate<Logger>()));
register<UserRepo>(() => UserRepo(locate<Database>()));

// Resolves entire dependency chain
final repo = locate<UserRepo>();

Async Dependencies

register<Future<Database>>(() async {
  final db = Database();
  await db.initialize();
  return db;
});

final db = await locate<Future<Database>>();

Real-World Examples

Flutter App Setup

void main() {
  setupDependencies();
  runApp(MyApp());
}

void setupDependencies() {
  // Core services
  register<Logger>(() => ConsoleLogger());
  register<HttpClient>(() => HttpClient());

  // Repositories
  register<AuthRepository>(() => AuthRepository(
    client: locate<HttpClient>(),
    logger: locate<Logger>(),
  ));

  // Use cases
  register<LoginUseCase>(() => LoginUseCase(
    authRepo: locate<AuthRepository>(),
  ));
}

// In your widgets
class LoginScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final loginUseCase = locate<LoginUseCase>();
    // Use the dependency
  }
}

Testing with Mocks

void main() {
  setUp(() {
    clear(); // Reset before each test

    // Register mocks
    register<AuthRepository>(() => MockAuthRepository());
    register<LoginUseCase>(() => LoginUseCase(
      authRepo: locate<AuthRepository>(),
    ));
  });

  test('login success', () {
    final useCase = locate<LoginUseCase>();
    // Test with mock dependency
  });
}

Performance

Benchmarked on Apple M1:

Operation Throughput Latency
locate() 11M ops/sec ~0.09µs
create() 15M ops/sec ~0.06µs
isRegistered() 44M ops/sec ~0.02µs
register() 7M ops/sec ~0.13µs

O(1) Verified: Time complexity remains constant from 10 to 10,000+ registered services.

Minimal Overhead: Only ~2x slower than direct HashMap access.

API Reference

Registration

void register<T>(
  T Function() factory, {
  String? instanceName,
  void Function(T)? dispose,
})

Resolution

T locate<T>({String? instanceName})         // Get/create singleton
T create<T>({String? instanceName})         // Always create new
bool isRegistered<T>({String? instanceName}) // Check registration

Cleanup

void remove<T>({String? instanceName})  // Remove + call dispose
void clear()                             // Remove all + dispose all

Direct Class Access

ServiceLocator.I.register<T>(...)
ServiceLocator.I.locate<T>(...)
ServiceLocator.I.create<T>(...)
ServiceLocator.I.remove<T>(...)
ServiceLocator.I.isRegistered<T>(...)
ServiceLocator.I.clear()

Examples

See the example folder for a complete working example.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

BSD-3-Clause - see LICENSE