@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 @Environmet are as follows:
- @Environment(.colorScheme) – Access the current system appearance (light or dark mode).
- @Environment(.dismiss) – The modern way to dismiss a view (iOS 15+).
- @Environment(.locale) – Access the current locale or language settings chosen by the user.
- @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"))