Project layout
Every folder in a generated project, what lives there, and why.
This page describes the full layout produced by swiftspawn new, file by file.
Top level
Section titled “Top level”MyApp/├── MyApp.xcodeproj # real Xcode project (Xcode 26 format)├── Package.swift # SPM manifest, with auto-managed dependency markers├── Package.resolved # SPM lockfile├── .swiftspawn.yml # CLI's project config├── .swiftlint.yml # SwiftLint config├── .swiftformat # SwiftFormat config├── .gitignore├── README.md├── Configs/ # build configurations│ ├── Debug.xcconfig│ ├── Staging.xcconfig│ └── Release.xcconfig├── MyApp/ # source tree└── Tests/ # test tree (created on first --with-tests)MyApp.xcodeproj is a real Xcode 26 project, not a generator output that needs further processing. It uses PBXFileSystemSynchronizedRootGroup, which means new files added on disk show up in Xcode automatically without editing pbxproj.
.swiftspawn.yml is the CLI’s source of truth for the project name, bundle id, deployment target, and similar config. Subsequent swiftspawn runs use it; never delete it.
Source tree
Section titled “Source tree”MyApp/├── App/│ ├── MyAppApp.swift # @main entry, hosts RootView│ ├── RootView.swift # NavigationStack + route switch (markers)│ ├── HelloView.swift # placeholder so the app launches│ └── DIContainer.swift # Factory container (markers)├── Infrastructure/│ ├── Networking/│ │ ├── APIClient.swift # URLSession-based client, interceptor chain│ │ ├── APIRequest.swift # typed request value│ │ ├── APIConfig.swift # base URL, default headers, auth strategy│ │ ├── AppError.swift # the app's error type│ │ ├── AuthInterceptor.swift # adds auth header to outgoing requests│ │ └── LoggingInterceptor.swift # DEBUG-only request/response logs│ ├── Routing/│ │ ├── Route.swift # the Route enum (markers)│ │ └── Router.swift # @Observable wrapping NavigationPath│ ├── Auth/│ │ └── TokenStore.swift # actor holding the auth token│ └── Logging/│ └── Log.swift # namespace over os.Logger├── Resources/│ ├── Assets.xcassets/│ └── Info.plist├── Features/ # one folder per feature│ └── Components/ # views shared across features└── Services/ # one trio per resource (flat)The application entry point and root navigation.
MyAppApp.swift:@mainstruct. Creates the sharedRouterandDIContainer, wrapsRootViewin aWindowGroup.RootView.swift: aNavigationStackbound toRouter.path, with aswitchoverRoutebetween markers. New screens get a case here automatically.HelloView.swift: a placeholder so a freshly scaffolded project launches without errors. Delete it when you have real screens.DIContainer.swift: the FactoryContainerextension. Service registrations live here between markers.
Infrastructure/
Section titled “Infrastructure/”The pieces every app shares. Small enough to read in an afternoon.
- Networking is a
URLSession-backedAPIClientwith an interceptor chain. Interceptors get a chance to mutate outgoing requests and incoming responses;AuthInterceptorinjects the token,LoggingInterceptorlogs both. - Routing is an enum + an
@Observablewrapper overNavigationPath. Each new screen adds one case to the enum and one arm to the root switch. - Auth is just a
TokenStoreactor. Replace its body with Keychain access in production. - Logging is a namespace with one logger per category over
os.Logger. FilterConsole.appby your bundle id and category to read the trace.
Resources/
Section titled “Resources/”Standard SwiftUI resources: Assets.xcassets for images and colors, Info.plist for app metadata.
Features/
Section titled “Features/”One folder per feature. Empty after new; populated by generate feature and generate screen.
A typical feature looks like:
Features/Movies/├── Models/│ ├── Movie.swift│ └── Genre.swift├── MovieList/│ ├── MovieListView.swift│ └── MovieListViewModel.swift├── MovieDetail/│ ├── MovieDetailView.swift│ └── MovieDetailViewModel.swift├── MovieEdit/│ ├── MovieEditView.swift│ └── MovieEditViewModel.swift└── MoviePosterView.swift # standalone view (no subfolder)Screens get subfolders, views don’t. See Vocabulary.
Features/Components/
Section titled “Features/Components/”The default home for generate view <Name> when no --in is given. Use it for views shared across features (avatars, badges, error banners).
Services/
Section titled “Services/”Flat. One trio per resource: protocol, implementation, mock.
Services/├── MovieService.swift # protocol├── MovieServiceImpl.swift # real, calls APIClient├── MockMovieService.swift # canned responses for tests/previews├── UserService.swift├── UserServiceImpl.swift└── MockUserService.swiftWhy flat? Services are referred to from many features; nesting them inside one feature folder hides them from the others. The CRUD recipe and generate service always write here.
Tests/└── MyAppTests/ ├── Features/ │ └── Movies/ │ └── MovieList/ │ └── MovieListViewModelTests.swift └── Services/ └── MovieServiceTests.swiftTests mirror the source layout. --with-tests on any generator emits the matching test stub.
Configs
Section titled “Configs”Three xcconfigs corresponding to three build configurations:
Debug.xcconfig: local development. Logging on, base URL points to dev.Staging.xcconfig: pre-production. Logging on, base URL points to staging.Release.xcconfig: production. Logging off, base URL points to prod.
APIConfig.swift reads these via Bundle.main.infoDictionary to pick the right base URL and auth at runtime.
See also
Section titled “See also”- Markers for how the CLI safely edits files.
- Architecture for how the layers interact.
- Vocabulary for what each term means.