Jul 15, 2026

Enums as Namespaces

Enum Swift SwiftUI
Enums as Namespaces

Using Enums as Namespaces in Swift

Introduction

Swift enums are one of the most powerful types in the language. Most developers use them to model a fixed set of related values, such as navigation destinations, application state, network results, or user roles.

However, enums have another extremely useful purpose that often gets overlooked: acting as a namespace.

In many projects, you'll eventually find yourself collecting related constants, configuration values, helper methods, feature flags, API endpoints, validation rules, and other code that doesn't naturally belong to a specific type. The question then becomes: where should that code live?

Some developers reach for global constants. Others create utility structs. Still others create singleton objects. While all of these approaches work, there is often a cleaner solution.

In this blog post, we'll look at how enums can be used as namespaces, why they're often preferable to utility structs, how they differ from singletons, and when they are and are not appropriate.


The Problem

As Swift projects grow, it becomes increasingly common to accumulate values that need a home.

Consider this example of three properties that are created outside of any struct, class or enum:

let cornerRadius: CGFloat = 12let padding: CGFloat = 20let animationDuration: Double = 0.3

There is nothing technically wrong with this code, but these constants now live in the global namespace.

As your project grows, global values can become difficult to discover and maintain. They also increase the likelihood of naming conflicts. It is the "difficult to discover" concept that I find most problematic, particularly if I have been away from the project for a while.

Even worse, future developers may have no idea where a value came from when they encounter code like this:

.padding(padding)

The context is missing.


A Better Solution

One way to solve this problem is to create a namespace.

A namespace is a way of grouping related constants, functions, and types together under a common name.

All you need to do is to create the enum and then define your values as static properties or methods/functions.

enum UI {    // Static stored properties    static let cornerRadius: CGFloat = 12    static let padding: CGFloat = 20    static let animationDuration: Double = 0.3    // Static computed properties    static var cardShadowRadius: CGFloat {        cornerRadius / 2    }    // Static methods    static func opacity(        isEnabled: Bool    ) -> Double {        isEnabled ? 1.0 : 0.5    }    static func cardColor(        isSelected: Bool    ) -> Color {        isSelected ? .teal : .yellow    }}

Now, you get the benefit of Xcode's code completion. When you type the enum name followed by a period, You get a list of all the enum's static properties and methods to choose from. All of theses properties and methods for the enum are prefaced with the M icon which stands for member.

image-20260605115645096

VStack {    Text("Hello")}.padding(UI.padding).background(    UI.cardColor(isSelected: true),    in: .rect(cornerRadius: UI.cornerRadius)).shadow(radius: UI.cardShadowRadius).opacity(UI.opacity(isEnabled: true))

The code is now much more self-documenting.

When you see:

UI.padding

you immediately know where the value comes from and what it represents.


Why Use an Enum?

At this point you might be wondering why we chose an enum rather than a struct or class.

The answer is simple: intent.

An enum with no cases cannot be instantiated.

enum UI {    static let padding: CGFloat = 20}

Attempting to create an instance results in a compiler error:

let ui = UI()

This tells every developer reading the code:

This type exists solely to organize related functionality.

That is exactly what we want from a namespace.


Why Not Use a Struct?

Many developers use a struct instead.

struct UI {    static let padding: CGFloat = 20}

This works perfectly well.

The problem is that the struct can still be instantiated.

let io = UI()

The instance serves no purpose because every member is static.

By using an enum, we prevent accidental instantiation entirely and make our intentions clearer.


What else can go in an enum namespace?

We have already seen static stored and computed properties along with static methods, but what else can go in an enum namespace? The answer is quite a bit, provided it is static.

Nested Enum namespaces

A nested enum is perfect when you want to create additional namespaces.

enum API {    static let baseURL =        "https://api.example.com"    enum Endpoints {        static let users = "/users"        static let videos = "/videos"        static let playlists = "/playlists"    }}// Example Usage:let url = API.baseURL + API.Endpoints.videos

Nested Enum with Cases

You can combine a namespace enum with another enum that actually has cases.

enum Theme {    enum Style {        case light        case dark        case system    }// Example Usage:let currentStyle: Theme.Style = .system

Nested Struct

A nested struct is useful when the namespace owns a related model.

enum AppInfo {    struct Version {        let major: Int        let minor: Int        let patch: Int    }}// Example Usage:let version = AppInfo.Version(    major: 1,    minor: 2,    patch: 0)

Nested Class

A nested class is useful when the namespace owns a related service or object that needs to maintain state over time.

enum Utilities {    final class Counter {        private(set) var count = 0        func increment() {            count += 1        }    }}// Example Usage:let counter = Utilities.Counter()counter.increment()print(counter.count)

Nested Protocols

Protocols are a great candidate because they often describe a group of related behaviors.

In this example, it is obvious that the protocol belongs to your networking layer.

enum Networking {    protocol Requestable {        var endpoint: String { get }    }}// Example Usage:struct UserRequest: Networking.Requestable {    let endpoint = "/users"}

Type Alias

Type aliases can become difficult to locate when they are global. It prevents global type aliases from cluttering a project

enum AppTypes {    typealias Completion =        (Result<Void, Error>) -> Void}// Example Usage:func save(    completion: AppTypes.Completion) {    // ...}

Enum Namespace vs Singleton

This is where many developers become confused.

At first glance these patterns can look similar.

Singleton

final class AppInfo {    static let shared = AppInfo()    private init() {}    var appName = "My App"}// Example Usage:AppInfo.shared.appName

Enum Namespace

enum AppInfo {    static let appName = "My App"}// Example Usage:AppInfo.appName

Although the call sites appear similar, the designs are fundamentally different. The singleton represents a single shared object that can maintain state throughout the life of the application. The enum namespace simply groups related values and functionality together and can never be instantiated.

In the case of the singleton, this is possible.

AppInfo.shared.appName = "My New App"

Whereas the enum namespace would produce an error if we tried to do this

AppInfo.appName = "My New App"

When to Use a Namespace

Namespaces are ideal when:

  • Everything is static
  • No state is stored
  • No instance should ever exist
  • The goal is organization

Examples include things such as layout constants, API endpoints, validation rules etc


When to Use a Singleton

Singletons are appropriate when:

  • Shared state exists
  • Resources are managed
  • One instance must exist
  • The object has a lifecycle

Examples include network managers, cache managers database coordinators etc.

These are fundamentally different from namespaces.


Benefits of Enum Namespaces

As we have discovered, enums:

  • Prevent instantiation
  • Improve discoverability
  • Reduce global namespace pollution
  • Make code more self-documenting

Drawbacks of Enum Namespaces

Like any pattern, enum namespaces are not perfect.

  • They cannot store state
  • They can become dumping grounds so avoid giant namespaces and create focused ones.

Conclusion

Using enums as namespaces is one of those simple Swift techniques that can significantly improve code organization.

By defining an enum with no cases and adding static members, you create a logical grouping of related functionality while preventing accidental instantiation. The pattern communicates intent clearly, reduces namespace pollution, and keeps code easier to discover and maintain.

Just remember that namespaces are not a replacement for extensions or singletons.

If functionality naturally belongs to an existing type, prefer an extension. If you need shared state or resource management, consider a singleton, class, actor, or protocol-based service.

But when all you need is a place to organize related constants, helper methods, and configuration values, an enum namespace is often the cleanest solution available in Swift.