Make Command Reference
This page is the exhaustive lookup for commands that create controllers, commands, jobs, schedules, events, models, migrations, and named queues. Each entry records the files and registration points the command changes.
Use the linked feature guide when you need to implement the generated resource. Use this reference when you need exact placement, wiring, removal, or shared-option behavior.
In a multi-app Project, run make commands through the app that owns the resource:
forj admin make:controller users
forj admin make:job reports:export
forj admin make:schedule audit:cleanupThe app prefix chooses the registration point. forj admin make:* creates the generated resource under internal/... and writes the registration and Wire changes into app/admin/...; unprefixed forj make:* creates the resource under internal/... and writes registration changes to the default app under app/....
This keeps app composition in the owning app while shared domain code can still live under internal/....
Choose a Command or Workflow
make:controllercreates an HTTP controller and registers its routes.make:appcreates an additional runnable app.make:commandcreates an App command and exposes it to Kong.make:jobcreates a queue job and registers its handler.make:queuecreates named queue configuration and a generated accessor.make:schedulecreates and registers a recurring task.make:eventcreates a typed application event.make:subscribercreates and registers an event subscriber.make:modelderives a model and repository from a database table.make:migrationcreates timestamped up and down SQL files.
Shared workflows apply across those generators:
- Package placement explains grouped names and feature ownership.
- Removing generated resources previews and reverses managed changes.
- Opening generated files opens the primary generated source in your editor.
- Output overrides selects a non-default package directory.
- Ownership and verification separates generated scaffolding from App behavior and proves the result.
Command Reference
Some make commands are native GoForj commands and some are App commands. During development, use the same forj prefix for both. Native GoForj commands win on name collisions; otherwise GoForj delegates to the active app through the same source-aware path as forj run.
For an additional app, prefix the command with the app name. The generated resource stays under internal/..., while registration changes go to the owning app under app/<name>/....
make:app
Create an additional app:
forj make:app adminWithout selection flags in an interactive terminal, the command opens the app wizard. In non-interactive use, or when scripting an exact selection, pass flags:
forj make:app admin --components web-api,jobs
forj make:app statuspage --components web-api,web-ui --starter-kit vueUse --without to remove components from the project-derived default selection. Use --help-format framework, --help-format external_cli, or --help-format guided to choose the App command-help style. --skip-wire renders the App files without regenerating Wire; it is intended for generator debugging or a workflow that deliberately runs Wire separately.
The command creates the conventional binary entrypoint under cmd/admin/, app-owned composition under app/admin/, and app-specific Wire graph under app/admin/wire/. Exact files depend on the selected components; a CLI-only app does not receive HTTP, scheduler, or worker files merely because another app has them.
It also records the app's render metadata under top-level apps in .goforj.yml:
apps:
admin:
components: [web_api, jobs]
starter_kit: noneThe interactive wizard enrolls an app with HTTP, jobs, or schedules in forj dev and proposes the combined run command. A CLI-only app remains unenrolled. Review the Dev Run step when the app needs a narrower long-running command.
Flag-driven and non-interactive creation do not enroll the app unless --dev-run is explicit:
forj make:app admin --components web-api,jobs --dev-run run--dev-run run selects the development supervisor command; it does not add runtime capabilities. A runtime-capable binary already defaults to run when launched without arguments.
Remove only the conventional App files and metadata created by make:app with:
forj make:app admin --removeRemoval is conservative and does not delete unknown app-owned files or migration history. See Apps for the ownership model and forj dev for normal lifecycle configuration.
make:controller
Generate an HTTP controller for the package that owns the route.
forj make:controller reportsThe name controls both the package path and the starter route, /reports.
Prefix the command when an additional app owns the route:
forj admin make:controller usersRemove the generated controller and its managed registrations with:
forj make:controller reports --removemake:command
Generate an App command.
forj make:command reports:syncUse --name to override the exposed command signature independently from the generated type and file:
forj make:command Sync -d ./internal/billing/reports --name reports:syncforj make:command reports:sync --removemake:job
Generate a queue job and select its default queue.
forj make:job billing:sync-reports --queue billingforj make:job billing:sync-reports --removemake:queue
Add a named queue resource.
forj make:queue reports --workers 2Run forj make:queue without a name in an interactive terminal to use the resource wizard.
Use --name production-report-jobs when the backend queue name should differ from the reports resource name. Use --env-file to update a file other than .env.
forj make:queue reports --removePass the same --env-file during removal when creation did not update .env.
make:schedule
Generate a recurring task.
forj make:schedule reports:daily --every 24hforj make:schedule reports:daily --removeIf --every is omitted, the generated starter interval is 1h.
make:event
Generate an application event type.
forj make:event billing:invoice-paidforj make:event billing:invoice-paid --removeRemoval deletes the generated type, but it does not remove application code that refers to it.
make:subscriber
Generate a subscriber for an application event.
forj make:subscriber billing:invoice-paidUse --bus audit to target a named event bus configured by EVENTS_AUDIT_DRIVER.
forj make:subscriber billing:invoice-paid --removePass the same --bus value used during creation. Removal deletes the generated subscriber, its provider, and its subscription block.
make:model
Generate a model and repository helpers in an explicit package.
forj make:model invoices --package billingThe positional argument is the exact name of an existing table. The generator inspects invoices through the default database connection, so that connection must be available. It does not create or migrate the table, and make:model does not select a named connection. The generated Go type and filename are singularized from the inspected table name; when an exact table is missing, the command may suggest an existing singular or plural variant. Models use --package rather than -d because their placement follows database table ownership.
forj make:model invoices --package billing --removeIf the model already exists, the command updates its schema-derived model definition while preserving the repository section.
By default, an ungrouped model is written under ./internal/models. Use --encrypt column_name or --compress column_name to add the corresponding generated field handling; repeat the option or pass comma-separated names for multiple fields.
make:migration
Generate SQL migration files.
forj make:migration create_invoice_tablesUse --connection for a non-default migration stream. Drivers come from DB_SUPPORTED_DRIVERS, falling back to DB_DRIVER.
forj make:migration create_invoice_tables --removeRemoval deletes timestamped up and down files matching the migration name.
How Package Placement Works
Make commands prefer colocated packages, but command names should stay operationally short.
Use category:action for application command names:
forj make:command reports:syncThis creates internal/reports/sync_cmd.go. Use two segments unless the extra segment is truly part of the operator-facing command. When the command belongs in a deeper package, keep the command name short and use -d to control file placement.
See Naming Conventions for command, job, event, schedule, route, and named resource names.
Bare commands
A bare application command is App-wide:
forj make:command syncIt creates internal/cmd/sync_cmd.go. Use a grouped name when a feature package owns the command:
forj make:command reports:syncThis creates internal/reports/sync_cmd.go and exposes reports:sync. If operator naming and package placement differ, keep the command name short and use -d:
forj make:command reports:sync -d ./internal/opsThe file moves to internal/ops/sync_cmd.go, but the exposed command remains reports:sync.
Go package names
Generated package declarations use compact lowercase Go names. For example:
forj make:controller BillingPortalThis creates a billingportal package, not billing_portal. File names can use underscores, but package names should remain short lowercase identifiers.
Organize by package ownership
Make commands organize code around the package that owns the behavior, not around global controllers, jobs, models, or commands directories.
internal/reports/
controller.go
sync_cmd.go
generate_job.go
daily_schedule.go
report_generated_event.go
report_generated_subscriber.go
report.go
service.goEvery .go file in that directory declares package reports, so the package name provides the scope. Controller, SyncCmd, GenerateJob, DailySchedule, Report, and Service are different entry points and collaborators inside one ownership boundary.
Read grouped generator names from left to right:
forj make:controller reportscreatesinternal/reports/controller.go.forj make:job reports:generatecreatesinternal/reports/generate_job.go.forj make:schedule reports:dailycreatesinternal/reports/daily_schedule.go.
Controllers are package anchors, so the full grouped name becomes the controller package. For jobs and schedules, the leading segments select the package and the final segment names the generated entry point. Start with a flat package such as internal/reports; add nesting only when another package boundary clarifies ownership.
The generated entry points should stay thin:
HTTP request -> reports.Controller -> reports.Service
CLI command -> reports.SyncCmd -> reports.Service
Queue worker -> reports.GenerateJob -> reports.Service
Scheduler process -> reports.DailySchedule -> reports.Service
Event bus -> reports.ReportGeneratedSubscriberThey translate input, call package services, and return output. Services own workflows and receive repositories, clients, caches, queues, storage, and events through explicit constructor dependencies. Keeping related entry points together makes imports reveal ownership, keeps Wire constructors close to what they construct, and lets a feature move or shrink as one visible unit.
Shared Options
Removing Generated Resources
Removal uses the same name, package, connection, bus, output, and env-file flags as creation. Pass the same options so the generator resolves the same file and registration entries.
Use --dry-run to preview file and wiring cleanup:
forj make:controller reports --remove --dry-run--remove resolves the conventional generated path and removes the file at that path; it does not distinguish an untouched generated file from one you later edited. It also removes the matching generated registration entries. Migration removal deletes matching timestamped up/down files by migration name.
Commit or preserve application changes before removal, and inspect --dry-run output carefully. Removal does not search for tests, manually added references, or business code elsewhere, so the following build is what exposes remaining dependencies.
After removing a wired resource, rebuild the graph:
forj buildThe build exposes application code that still refers to the removed type, route, command, repository, job, schedule, or subscriber.
Opening Generated Files
Source-generating make commands can open their primary generated file after a successful run:
forj make:controller reports -o
forj make:job billing:sync-reports --openThis applies to controllers, commands, events, subscribers, jobs, schedules, models, and migrations. A migration opens its first generated up migration. make:queue only updates configuration, so it has no source file to open.
Use --no-open to suppress opening for one run. Apps can set:
FORJ_MAKE_OPEN=auto
FORJ_EDITOR=FORJ_MAKE_OPEN accepts:
| Value | Behavior |
|---|---|
auto | Open only in an interactive terminal when CI is not active. |
always | Try to open after every successful generator run. |
never | Open only when the command explicitly uses --open or -o. |
Automatic opening stays quiet when it cannot resolve an editor. An explicit --open, or FORJ_MAKE_OPEN=always, prints a warning instead.
Set FORJ_EDITOR to pin the command when automatic detection is not what you want:
FORJ_EDITOR="code --reuse-window --goto {location}"
FORJ_EDITOR="goland --line {line} {file}"The command supports {file} for the absolute generated path, {line} for the line number, and {location} for both as path:line. Without FORJ_EDITOR, GoForj checks terminal editor hints, then running GUI editors, then commands on PATH. Its editor preference is GoLand, Cursor, VS Code, Zed, then IntelliJ IDEA, while preferring an already-running editor over launching a different one.
Output Overrides
Ungrouped resources use these source-owned defaults:
| Command | Default output |
|---|---|
make:command | ./internal/cmd |
make:job | ./internal/jobs |
make:schedule | ./internal/schedules |
make:event | ./internal/events |
make:subscriber | ./internal/events |
make:model | ./internal/models |
Use -d when the default grouped package path is not the package you want:
forj make:command reports:sync -d ./internal/billing/reports
forj make:job billing:sync-reports -d ./internal/ops
forj make:schedule reports:daily -d ./internal/billing/reports
forj make:event billing:invoice-paid -d ./internal/billing/events
forj make:subscriber billing:invoice-paid -d ./internal/billing/eventsThe override controls the file location and package name. The grouped command name can still express the command, job, or event identity.
make:model uses --package instead of -d because models and repositories are generated around database table ownership.
Ownership and Verification
What Belongs to You
Generated files are starting points. Your App still owns:
- business logic and service methods
- constructor parameters for application services
- route behavior, validation, and response shape
- command input parsing and console output
- job payloads and handler behavior
- schedule intervals and handler behavior
- event payloads and subscribers
- migration SQL
- model relationships and repository options
Keep dependencies explicit. If a generated controller, command, or job needs an application service, add that service constructor to the right provider set and let Wire pass it in.
Verify
After running a make command, verify the graph and the exposed runtime surface:
forj build
forj route:listUse route:list for controllers. For commands, run the generated command signature through forj <command>. Use forj run <command> only when you want to force App command execution explicitly.
Common Mistakes
Common mistakes
- Do not create one package per generated file.
- Do not collect every controller, job, command, and service in one global package.
- Do not make operator-facing command names longer merely to mirror package depth.
- Do not use snake case package names.
- Do not put business workflows directly in generated entry points.
- Do not hand-edit generated wiring before using the make command path.
Next Steps
- Controllers shows the HTTP boundary around services.
- Commands shows App-owned CLI entry points.
- Naming Conventions defines stable operational names.
- Wiring Recipes shows where generated and hand-written providers belong.
- CLI Reference lists project-level commands and App command patterns.