--- title: Application lifecycle description: "What happens when an application binary starts: configuration, the backpack container, plugin ordering, Register and Boot, and database-dependent boot work." section: architecture order: 30 --- # Application lifecycle Every run of an application binary, whether it serves HTTP or runs a single console command, goes through the same start-up. `summer build` generates the `main.go` that performs it, so you never write it by hand. ## Start-up sequence The generated `main` does the following, in order: 1. Loads configuration with `compass.Load` from the `config/` directory, applying the environment directory and `SUMMER_` variables. 2. Creates the application container with `backpack.New`. 3. Activates the plugins listed in `summer.yaml` with `party.Activate`. 4. Collects the console commands: the framework's runtime commands (from `lagoon.RuntimeCommands`, `conga.RuntimeCommands`, `surf.ServeCommand`, `surf.RouteListCommand` and `cabana.RuntimeCommands`), then the commands of every plugin that implements `pact.HasCommands`. 5. Publishes the command set as a `bonfire.Catalog`, so the scheduler can run commands in-process. 6. Runs the command named on the command line. ## Plugin ordering `party.Activate` selects the plugins by ID and orders them so that every plugin comes after the plugins its `party.Plugin.Requires` lists. It fails before any plugin code runs when an ID is empty, duplicated or not compiled in, when a required plugin is missing, or when the requirements form a cycle. ## Register, then Boot Activation runs in phases, and each phase finishes for every plugin before the next begins: 1. `backpack.App.SetPlugins` records the complete plugin set, so `backpack.App.HasPlugin` answers correctly from the first Register onwards. 2. The embedded defaults of every plugin that implements `pact.HasConfig` are merged into the configuration under the plugin ID. 3. `party.Plugin.Register` runs for every plugin. Publish services here; do not use other plugins' services yet. 4. The framework publishes the translator and the mailer, and registers each plugin's translations and mail templates. 5. `party.Plugin.Boot` runs for every plugin. Look up services, register event listeners and extend other plugins here. This is the WinterCMS `register` and `boot` split: when any Boot runs, every plugin has already registered. ## The container `backpack.App` is the application container that Register and Boot receive. It holds the configuration in `backpack.App.Config`, the event bus in `backpack.App.Events` and a typed service registry. Nothing in it is process-global, so two applications in one test do not share state. Services are keyed by their Go type. A plugin publishes a value with `backpack.App.Publish` and another plugin reads it with `backpack.App.Lookup` and the same type argument. Publish under an interface type when consumers should not depend on your implementation: ```go src=modules/backpack/example_test.go#ExampleApp_Publish app := backpack.New(&compass.Config{}) app.SetPlugins([]string{"acme.greeter", "acme.blog"}) // acme.greeter, in its Register step: publish under the interface type. var greeter Greeter = englishGreeter{} if err := app.Publish(greeter); err != nil { fmt.Println(err) return } // acme.blog, in its Boot step: look the service up by the same type. if app.HasPlugin("acme.greeter") { if found, ok := app.Lookup[Greeter](); ok { fmt.Println(found.Greet("blog")) } } // A second Publish under the same type is refused. fmt.Println(app.Publish(greeter) != nil) // Output: // Hello, blog // true ``` ## Capability interfaces Beyond the four `party.Plugin` methods, a plugin declares what it contributes by implementing interfaces from [pact](../../modules/pact/README.md). The framework package that owns a capability finds it with a type assertion: surf asks for `pact.HasRoutes` and `pact.HasMiddleware`, lagoon for `pact.HasMigrations`, cabana for `pact.HasAdminControllers`, conga for `pact.HasJobs` and `pact.HasSchedule`. A plugin that does not implement an interface simply does not take part in that capability. ## Database-dependent boot work Boot runs before any command opens the database: `migrate` and `serve` open it after activation, and commands such as `key:generate` never open it. Code that needs the database handle during boot, such as registering GORM callbacks, therefore goes through `lagoon.OnDatabase`. It runs the function immediately when the database is already published, and otherwise queues it until `lagoon.Publish` makes the shared `*sql.DB` and `*gorm.DB` handles available. An error from a queued function is returned by `lagoon.Publish`, so the command that opened the database fails instead of running with a half-registered plugin. [Extending plugins](../plugins/extending.md) shows where GORM callbacks fit.