Service providers are where your addon wires itself into the application. An addon typically has three: the main YourAddonServiceProvider (views, config, translations, hooks, commands, schedule, middleware aliases, view composers), a RouteServiceProvider that maps Routes/web.php and Routes/api.php with the right middleware, and an EventServiceProvider with a $listen array mapping events to listeners (plus optional subscribers). All providers must be listed in the providers array of module.json to be registered.
The split between methods matters: register() is for container bindings and registering the other providers; boot() is for everything that bootstraps behavior — loading hook files from hooks/, loadTranslationsFrom(), mergeConfigFrom() plus publishes() for config, loadViewsFrom() with publishable view paths, loadMigrationsFrom(), registering artisan commands (guarded by runningInConsole()), scheduling via callAfterResolving(Schedule::class, ...), and aliasMiddleware() for custom middleware. The container supports singleton bindings, interface-to-implementation bindings for dependency injection, and contextual bindings; deferred providers ($defer = true with a provides() list) delay loading until the service is actually needed.
Practical notes: keep each provider focused on its role, fire hooks from listeners so other addons can react, and remember that route providers can conditionally load separate route files per user role. Users can publish your config, views, and assets with php artisan vendor:publish using the tags you define.