Storyboard
programmatically
iOS development
Swift
UIKit

How can I load storyboard programmatically from class?

Master System Design with Codemia

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

Introduction

Loading a storyboard programmatically is just a matter of instantiating UIStoryboard and then asking it for either its initial view controller or a specific scene identifier. The important distinction is whether you want the storyboard's configured entry point or a known view controller class tied to a storyboard id. Once you understand that split, programmatic storyboard loading becomes predictable instead of magical.

Instantiate the Storyboard First

A storyboard is identified by its file name without the .storyboard extension. You create it with UIStoryboard(name:bundle:).

swift
import UIKit

let storyboard = UIStoryboard(name: "Main", bundle: nil)

That line does not create a screen yet. It only gives you access to the scenes defined in that storyboard.

Loading the Initial View Controller

If the storyboard has an initial view controller configured in Interface Builder, you can load it directly:

swift
1import UIKit
2
3func makeInitialController() -> UIViewController? {
4    let storyboard = UIStoryboard(name: "Main", bundle: nil)
5    return storyboard.instantiateInitialViewController()
6}

This is useful when a storyboard represents a flow and already has the correct entry point configured.

If you are bootstrapping the app manually, you can assign that controller to the window:

swift
1if let sceneDelegate = UIApplication.shared.connectedScenes.first?.delegate as? UIWindowSceneDelegate,
2   let windowScene = sceneDelegate.window??.windowScene,
3   let root = makeInitialController() {
4    let window = UIWindow(windowScene: windowScene)
5    window.rootViewController = root
6    window.makeKeyAndVisible()
7}

In practice, most apps do this in SceneDelegate or equivalent app startup code.

Loading a Specific View Controller by Identifier

If you want a particular scene, set a Storyboard ID in Interface Builder and instantiate it explicitly.

swift
1import UIKit
2
3func makeSettingsController() -> SettingsViewController {
4    let storyboard = UIStoryboard(name: "Settings", bundle: nil)
5    guard let controller = storyboard.instantiateViewController(
6        withIdentifier: "SettingsViewController"
7    ) as? SettingsViewController else {
8        fatalError("SettingsViewController not found in storyboard")
9    }
10    return controller
11}

This is the most common programmatic pattern because it is explicit and type-checked with the cast.

Wrapping Storyboard Loading in the Class Itself

A common convenience pattern is to put the factory method on the view controller class.

swift
1import UIKit
2
3final class ProfileViewController: UIViewController {
4    static func instantiate() -> ProfileViewController {
5        let storyboard = UIStoryboard(name: "Main", bundle: nil)
6        guard let controller = storyboard.instantiateViewController(
7            withIdentifier: "ProfileViewController"
8        ) as? ProfileViewController else {
9            fatalError("ProfileViewController scene is misconfigured")
10        }
11        return controller
12    }
13}

Then the caller writes:

swift
let controller = ProfileViewController.instantiate()
navigationController?.pushViewController(controller, animated: true)

This keeps storyboard details out of the rest of the codebase.

When Programmatic Loading Helps

Programmatic storyboard loading is useful when:

  • startup flow depends on login state or feature flags
  • you want one class method to own the storyboard id
  • you need to swap root view controllers at runtime
  • you are mixing storyboards with coordinator-style navigation

It gives you more control, but it also means configuration mistakes show up at runtime if storyboard names or identifiers do not match.

Common Pitfalls

  • Using the filename with .storyboard included instead of just the storyboard name.
  • Forgetting to set a Storyboard ID for scenes you want to load by identifier.
  • Assuming instantiateInitialViewController() will work when no initial controller is configured.
  • Force-casting without a helpful error message when configuration is wrong.
  • Spreading raw storyboard identifiers throughout the app instead of centralizing them.

Summary

  • Create a storyboard with UIStoryboard(name:bundle:).
  • Use instantiateInitialViewController() for the configured entry scene.
  • Use instantiateViewController(withIdentifier:) for specific scenes.
  • A class-level instantiate() helper keeps storyboard details localized.
  • Most runtime failures come from mismatched storyboard names or missing scene identifiers.

Course illustration
Course illustration

All Rights Reserved.