Getting Started

βš™οΈ
πŸ”’

Stop mixing secrets with configuration

Keep .env for secrets and stock Laravel keys. Move the non-secret configuration your app adds on top β€” third-party integrations, AI providers, payment gateways, microservice endpoints β€” into typed, version-controlled PHP classes with full IDE autocomplete and code review visibility.

Type-safe IDE autocomplete Version-controlled Reviewable in PRs

Why not just .env?

The .env approach

  • β€’ Not in version control β€” invisible in code review
  • β€’ Every value is a string β€” no type safety
  • β€’ New developers guess the correct setup
  • β€’ env() returns null after config:cache
  • β€’ No IDE autocomplete for configuration

The env-settings approach

  • β€’ In version control β€” reviewable in every PR
  • β€’ Fully typed β€” string, int, bool, float
  • β€’ Every environment's values are explicit in code
  • β€’ Works with config:cache β€” no env() calls
  • β€’ Full IDE autocomplete on every property

What this package does not replace

Laravel's own keys β€” and those of every third-party or community package β€” are turned into config() entries by config/*.php files during the LoadConfiguration bootstrap step, before the service container exists. A settings class resolves from that container, so it can never feed them. Those keys stay in .env, and this package makes no attempt to move them.

Stays in .env

Secrets
API keys, passwords, tokens.
Stock Laravel keys
APP_KEY DB_* MAIL_* QUEUE_*
Package keys
Anything a vendor's own config/*.php reads through env().

Moves to a settings class

Your own configuration
Non-secret values your app adds on top of Laravel.
In this demo
AiSettings PaymentSettings NotificationSettings ExternalApiSettings
Typed and reviewable
Lives in app/Settings/, visible in every pull request.

The boundary is enforced by Laravel, not by convention: put AiSettings::resolve() inside a config/*.php file and the app dies with Class "env" does not exist β€” the container isn't built yet.

πŸ“‹

Requirements

PHP 8.2+ Laravel 12.x / 13.x

No third-party runtime dependencies beyond Laravel itself.

1

Install the package

Install via Composer β€” that's all you need.

composer require hpwebdeveloper/laravel-env-settings
2

Publish the config file

This creates config/env-settings.php where you register your settings classes and configure the environment map.

php artisan vendor:publish --tag="env-settings-config"
3

Generate a settings class

Use the artisan command to scaffold a new settings class with typed properties. Each class defines what the values should be in each environment.

php artisan env-settings:make AiSettings \
  --properties="provider:string,text_model:string,max_tokens:int,temperature:float"

Settings class created: app/Settings/AiSettings.php
  β†’ Registered \App\Settings\AiSettings::class in config/env-settings.php

This creates app/Settings/AiSettings.php:

class AiSettings extends EnvironmentSettings
{
    public function __construct(
        public string $provider,
        public string $text_model,
        public int $max_tokens,
        public float $temperature,
    ) {}

    public static function development(): static
    {
        return new static(
            provider: 'ollama',        // free, local
            text_model: 'llama3.2',
            max_tokens: 1000,
            temperature: 0.9,
        );
    }

    public static function production(): static
    {
        return new static(
            provider: 'openai',       // paid, best quality
            text_model: 'gpt-4o',
            max_tokens: 8000,
            temperature: 0.2,
        );
    }
}
4

Register the settings class

A settings class stays inert until it is listed in the register array of config/env-settings.php β€” so env-settings:make appends that line for you. If it can't, because the config isn't published or has no register array, it says so and tells you what to add. Everything listed here is resolved once and bound as a singleton.

// config/env-settings.php
'register' => [
    \App\Settings\AiSettings::class,
],
5

Use it anywhere in your app

Access your settings via the global helper, the container, or type-hinted dependency injection β€” all three resolve the same singleton instance.

// Option A: Global helper (works everywhere)
$provider = envSettings(AiSettings::class)->provider;

// Option B: Container resolution
$ai = app(AiSettings::class);
$ai->text_model;  // 'gpt-4o' in production, 'llama3.2' in development

// Option C: Type-hinted injection (recommended in controllers/services)
public function __invoke(AiSettings $ai): View
{
    return view('dashboard', ['model' => $ai->text_model]);
}
6

Inspect with artisan commands

View the resolved values for the current environment or compare two environments side by side.

# Show resolved values for the current environment
php artisan env-settings:show "App\Settings\AiSettings"

# Show all registered settings classes
php artisan env-settings:show

# Compare development vs production
php artisan env-settings:diff "App\Settings\AiSettings" development production
πŸ€–

Real-World Example: AI/LLM Integration

AI-powered apps are the perfect use case β€” every environment uses different providers, models, and token limits. Instead of juggling .env variables, make each choice explicit and typed.

Prism prism-php/prism
use Prism\Prism\Prism;

$ai = envSettings(AiSettings::class);

$response = Prism::text()
    ->using($ai->provider, $ai->text_model)
    ->withMaxTokens($ai->max_tokens)
    ->withPrompt('Summarize...')
    ->asText();
Laravel AI laravel/ai
use Laravel\Ai\Facades\Ai;

$ai = envSettings(AiSettings::class);

$response = Ai::text()
    ->using($ai->provider, $ai->text_model)
    ->withMaxTokens($ai->max_tokens)
    ->withPrompt('Summarize...')
    ->asText();

In development: uses ollama + llama3.2 (free, local)  β€’  In staging: uses openai + gpt-4o-mini (balanced)  β€’  In production: uses openai + gpt-4o (best quality) β€” every change visible in a PR, fully typed, zero .env juggling.

πŸ”§

Advanced Features

Power-user features for teams that need flexibility.

πŸ”€

Local Overrides

Individual developers can override any settings class locally by creating an override class in app/Settings/Overrides/. Add that folder to .gitignore and enable via ENV_SETTINGS_OVERRIDE=true in your .env.

🌳

Root Settings

Compose multiple settings classes into a single root object. Access nested settings like envSettings(AppSettings::class)->ai->text_model for a unified configuration entry point.

πŸ—ΊοΈ

Environment Map

Map any APP_ENV value to a factory method. 'local' => 'development', 'prod' => 'production', etc. Customize in config/env-settings.php.

View on GitHub View on Packagist Back to Live Demo