vandor.
CLI Reference

vandor sync

Regenerate wiring code for your Vandor project

vandor sync

Regenerate the wiring code that connects your bounded contexts, domains, use cases, and services together.

Synopsis

vandor sync <scope> [flags]

Description

The sync command scans your project's filesystem to discover what components exist (contexts, domains, use cases, services) and then regenerates the *_gen.go wiring files that tie everything together. Think of it as the glue that keeps your FX module graph in sync with your actual code.

You do not normally need to run sync manually after using vandor add, because add triggers sync automatically. However, you will want to run it when you:

  • Manually create or move files
  • Delete components by hand
  • Want to verify that generated code is up to date (especially in CI)

Generated files are safe to regenerate. Files ending in _gen.go (like module_gen.go, contexts_gen.go, modules_gen.go) are fully managed by sync and will be overwritten on every run. Your hand-written files (like module.go) are never touched by sync.

Three Scopes

Sync operates at three levels, from narrow to broad:

vandor sync context

Refresh the wiring for a single bounded context. This regenerates the module_gen.go file inside that context's directory, which registers all discovered use cases and services with FX.

vandor sync context <name>

What it does:

  1. Scans the context directory for use cases, services, and domains
  2. Regenerates internal/context/<name>/module_gen.go

Example:

vandor sync context order

This updates internal/context/order/module_gen.go to include any new use cases or services you added to the order context.

What module_gen.go looks like:

// Code generated by vandor sync. DO NOT EDIT.
package order

import (
    "go.uber.org/fx"
    "project/internal/context/order/usecase"
    "project/internal/context/order/core/service"
)

var GeneratedModule = fx.Module("order-gen",
    fx.Provide(
        usecase.NewCreateOrder,
        usecase.NewCancelOrder,
        usecase.NewGetOrderByID,
    ),
    fx.Provide(
        service.NewPriceCalculator,
    ),
)

Meanwhile, your hand-written module.go composes GeneratedModule with any custom wiring you need, and sync will never overwrite it.

vandor sync core

Refresh the aggregate wiring files that live in internal/core/. These files pull all your individual context modules together into a single module graph.

vandor sync core

What it does:

  1. Scans all contexts in internal/context/
  2. Regenerates internal/core/contexts_gen.go (lists all context modules)
  3. Regenerates internal/core/modules_gen.go (aggregates everything)

What contexts_gen.go looks like:

// Code generated by vandor sync. DO NOT EDIT.
package core

import (
    "go.uber.org/fx"
    "project/internal/context/order"
    "project/internal/context/identity"
    "project/internal/context/catalog"
)

var ContextModules = fx.Options(
    order.Module,
    identity.Module,
    catalog.Module,
)

vandor sync all

Run context sync for every context, then run core sync. This is the most thorough option and ensures everything is consistent.

vandor sync all

What it does:

  1. Discovers all contexts in internal/context/
  2. Runs sync context for each one (regenerating each module_gen.go)
  3. Runs sync core (regenerating contexts_gen.go and modules_gen.go)

This is the command you want when you are not sure what changed, or when you want to make sure everything is fully up to date.

Flags

--check        CI mode: check if generated code is stale without modifying files.
               Exits with non-zero status if any _gen.go file would change.
--tidy auto|always|never   When to run go mod tidy (default: auto)

The --check Flag (CI Mode)

The --check flag is designed for continuous integration pipelines. Instead of regenerating files, it checks whether the current _gen.go files match what sync would produce. If there is a mismatch, it exits with a non-zero code.

# In your CI pipeline
vandor sync all --check

If the check fails, it means someone added or removed components without running sync. The CI output will tell you which files are stale:

STALE: internal/context/order/module_gen.go
STALE: internal/core/contexts_gen.go

Generated code is out of date. Run 'vandor sync all' to fix.
Exit code: 1

This is a great guard to add to your CI pipeline to catch forgotten syncs before they reach production.

Example CI step (GitHub Actions):

- name: Check generated code
  run: vandor sync all --check

How Sync Discovers Components

Sync does not maintain a manifest or database of your components. Instead, it reads directly from the filesystem:

  1. Contexts are discovered by scanning internal/context/ for directories that contain a module.go file.
  2. Use cases are discovered by scanning each context's usecase/ directory for Go files with New* constructor functions.
  3. Services are discovered by scanning each context's core/service/ directory for Go files with New* constructor functions.
  4. Domains are discovered by scanning each context's core/domain/ directory.

This means you can create components manually (without vandor add) and sync will pick them up, as long as they follow the expected directory structure and naming conventions.

Which Files Does Sync Touch?

Sync only writes to files that end in _gen.go:

FileScopePurpose
internal/context/<ctx>/module_gen.gosync contextWire use cases and services in one context
internal/core/contexts_gen.gosync coreList all context modules
internal/core/modules_gen.gosync coreAggregate module graph

Files that sync never touches:

  • module.go (your hand-written module composition)
  • Any use case, service, or domain files
  • Configuration files
  • Test files

Do not manually edit _gen.go files. They are overwritten every time sync runs. If you need custom wiring, put it in the non-generated module.go file in each context.

Examples

Sync everything after manual changes

# You manually created some files, now sync to pick them up
vandor sync all

Sync a single context after adding a use case

vandor sync context order

CI pipeline check

# Fail the build if generated code is stale
vandor sync all --check

Sync all, skip go mod tidy

vandor sync all --tidy never

When Do You Need to Sync Manually?

Most of the time, you do not. The vandor add command triggers sync automatically. But here are cases where manual sync is needed:

  1. You created files by hand -- For example, you wrote a new use case file directly instead of using vandor add usecase.
  2. You deleted files by hand -- If you removed a use case or service file, sync needs to update the generated wiring to remove the reference.
  3. You renamed files -- Moving or renaming Go files requires a sync to update imports.
  4. CI verification -- Use --check in CI to verify nothing is stale.

Troubleshooting

Import errors after sync

If you see import errors after syncing:

go mod tidy
vandor sync all

Sync does not detect my new use case

Make sure your use case follows the expected pattern:

  1. It is in the usecase/ directory of the context
  2. It has a New* constructor function
  3. The file compiles without errors
# Check that the file is valid Go
go vet ./internal/context/order/usecase/...

Generated file has wrong imports

Force a full re-sync:

vandor sync all --tidy always