What is @Environment and Why Is It Useful?

Sagnik SahaSagnik Saha
3 min read

@Environment is a special tool in SwiftUI that helps our view get information from the system or parent views — like whether the phone is in dark mode, which language the user is using, or whether a view should be dismissed — without us needing to pass that data manually through the view hierarchy.

Imagine every SwiftUI view is a room in a smart house. The house has a central system — it knows things like:

  • Is the light on or off? (dark mode)

  • What language should we speak? (locale)

  • Should this door (view) be closed? (dismiss)

Instead of each room needing to ask every other room what the setting is, the room can just ask the house using @Environment.

Common Use cases of @Environment are as follows:

  1. @Environment(.colorScheme) – Access the current system appearance (light or dark mode).

  2. @Environment(.dismiss) – The modern way to dismiss a view (iOS 15+).

  3. @Environment(.locale) – Access the current locale or language settings chosen by the user.

  4. @Environment(.horizontalSizeClass) – Retrieve the horizontal size class (compact or regular), which is useful for building adaptive layouts.

Now how to use this wrapper in Xcode?

@Environment(\.colorScheme) var colorScheme
// this check the mode of the device, e.g. DarkMode, LightMode 

@Environment(\.locale) var locale
// this check the language or region the user's device is set to.

Without @Environment, we'd have to pass all these values through every view manually — which is messy and hard to manage. With @Environment, our view can just ask the system for what it needs.

Important insights if you are making complex SwiftUI Apps

1. @Environment ≠ @EnvironmentObject

This is a common confusion!

@Environment gives us system-provided or parent-injected values (like colorScheme, locale, dismiss).

@EnvironmentObject is for custom shared data injected into the environment by your app (like AppSettings, UserSession, etc.).

We can’t use @EnvironmentObject unless it has been added via .environmentObject() — otherwise the app crashes.

2. Custom Environment Keys

Yes — we can create your own custom environment values using EnvironmentKey if you want to pass our own values down the view hierarchy in a SwiftUI-native way.

struct CustomKey: EnvironmentKey {
    static let defaultValue = "Hello XYZ"
}

extension EnvironmentValues {
    var customMessage: String {
        get { self[CustomKey.self] }
        set { self[CustomKey.self] = newValue }
    }
}

Then we can set and read it like this

// Set
SomeView().environment(\.customMessage, "Hello World")

// Read
@Environment(\.customMessage) var message

3. Environment values are read-only

Any @Environment value is read-only. We can't modify it directly. If we want to update shared state, we should use @State, @Binding, or @EnvironmentObject.

4. Nested views automatically inherit environment

When we use @Environment, the value is automatically passed down the view hierarchy. We don't need to “inject” it into every child — it's inherited, unless we override it using .environment() modifier.

This is super useful for settings like:

.environment(\.colorScheme, .dark)
.environment(\.locale, Locale(identifier: "es"))

5. Use .environment() modifier to override values

If we want to override an environment value for a specific view (like simulating dark mode or another language), you can use the .environment() modifier:

 Text("Hello")
    .environment(\.colorScheme, .dark)
    .environment(\.locale, Locale(identifier: "ja"))
0
Subscribe to my newsletter

Read articles from Sagnik Saha directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sagnik Saha
Sagnik Saha