Swift
iOS Development
Storyboards
Xcode
Programming Tips

How do I create a new Swift project without using Storyboards?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If you prefer building UIKit screens in code, you do not need storyboards at all. A storyboard-free project usually has fewer merge conflicts, a clearer startup path, and makes navigation and dependency injection easier to reason about.

What “Without Storyboards” Actually Means

A storyboard-based app normally tells iOS which storyboard to load at launch, and that storyboard creates the first view controller. A programmatic UIKit app does the same work in Swift instead:

  • create a UIWindow
  • create the root view controller
  • assign it to the window
  • make the window visible

The rest of the app can stay entirely in code.

Start with a UIKit App

If Xcode gives you a template that already avoids storyboards, that is the easiest path. If your template creates Main.storyboard, you can still convert the project cleanly.

The two main steps are:

  1. Remove storyboard references from the app configuration.
  2. Set the window and root controller yourself.

Delete Main.storyboard from the project, then remove the storyboard entry from the app configuration. In older project layouts this is often the Main storyboard file base name key. In scene-based setups, the scene manifest may also reference a storyboard.

Programmatic Launch with SceneDelegate

For scene-based UIKit apps, configure the initial window in SceneDelegate.

swift
1import UIKit
2
3final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
4    var window: UIWindow?
5
6    func scene(
7        _ scene: UIScene,
8        willConnectTo session: UISceneSession,
9        options connectionOptions: UIScene.ConnectionOptions
10    ) {
11        guard let windowScene = scene as? UIWindowScene else { return }
12
13        let window = UIWindow(windowScene: windowScene)
14        let rootViewController = UINavigationController(rootViewController: HomeViewController())
15
16        window.rootViewController = rootViewController
17        window.makeKeyAndVisible()
18        self.window = window
19    }
20}

This is the core of a storyboard-free UIKit startup. The app now launches into HomeViewController without any Interface Builder file.

Build the First Screen in Code

Your root controller can also be fully programmatic:

swift
1import UIKit
2
3final class HomeViewController: UIViewController {
4    private let titleLabel: UILabel = {
5        let label = UILabel()
6        label.translatesAutoresizingMaskIntoConstraints = false
7        label.text = "Hello, UIKit"
8        label.font = .preferredFont(forTextStyle: .largeTitle)
9        return label
10    }()
11
12    override func viewDidLoad() {
13        super.viewDidLoad()
14
15        view.backgroundColor = .systemBackground
16        view.addSubview(titleLabel)
17
18        NSLayoutConstraint.activate([
19            titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
20            titleLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor)
21        ])
22    }
23}

This gives you a running app with no storyboard and no nib file.

If Your App Uses AppDelegate Only

Some projects, especially older ones or intentionally simplified ones, create the window in AppDelegate instead of SceneDelegate.

swift
1import UIKit
2
3@main
4final class AppDelegate: UIResponder, UIApplicationDelegate {
5    var window: UIWindow?
6
7    func application(
8        _ application: UIApplication,
9        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
10    ) -> Bool {
11        let window = UIWindow(frame: UIScreen.main.bounds)
12        window.rootViewController = UINavigationController(rootViewController: HomeViewController())
13        window.makeKeyAndVisible()
14        self.window = window
15        return true
16    }
17}

You use this approach when the app does not rely on scene management. The principle is the same: iOS needs a window and a root controller, and you provide both yourself.

Why Teams Prefer This Approach

Programmatic UI is not automatically better, but it has some concrete advantages:

  • fewer XML merge conflicts in version control
  • easier conditional layout and feature flags
  • startup flow is visible in code
  • reusable custom views are straightforward to compose

It also encourages you to separate view construction from navigation and business logic, which often improves testability.

A Small Navigation Example

Once your app starts in code, pushing another screen is just normal UIKit:

swift
1import UIKit
2
3final class DetailsViewController: UIViewController {
4    override func viewDidLoad() {
5        super.viewDidLoad()
6        view.backgroundColor = .systemBlue
7    }
8}
9
10extension HomeViewController {
11    func showDetails() {
12        navigationController?.pushViewController(DetailsViewController(), animated: true)
13    }
14}

No storyboard segues are involved. All navigation rules stay in Swift, which many teams find easier to refactor.

Common Pitfalls

The most common mistake is deleting the storyboard file but leaving a storyboard reference in the app configuration. When that happens, the app still tries to load a non-existent storyboard and crashes at launch.

Another issue is forgetting to keep a strong reference to the window. If you create a local UIWindow and never store it, the UI may never appear.

Auto Layout problems are also common in fully programmatic screens. Every view created in code should either have a proper frame or constraints, and views using Auto Layout usually need translatesAutoresizingMaskIntoConstraints = false.

Finally, be clear about whether your project uses scenes. If you configure the window in the wrong lifecycle entry point, the app may compile but not show the expected UI.

Summary

  • A storyboard-free UIKit app creates its window and root controller in code.
  • Remove storyboard references from project configuration before deleting Main.storyboard.
  • In scene-based apps, create the window in SceneDelegate.
  • In non-scene setups, create the window in AppDelegate.
  • Programmatic UI reduces storyboard coupling and keeps startup flow explicit.

Course illustration
Course illustration

All Rights Reserved.