Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Toml Laravel Package

internal/toml

TOML 1.0.0/1.1.0 parser and encoder for PHP 8.1+. Parse TOML files straight into PHP arrays or encode arrays back to TOML, with support for tables, arrays of tables, and standard value types. A small, dependency-free tool for config files.

View on GitHub
Deep Wiki
Context7

Getting Started

internal/toml is a small, focused TOML 1.0/1.1 parser and encoder for PHP 8.1+. For a Laravel developer, treat it as a domain-config and TOML-generation utility, not as a wholesale replacement for Laravel’s PHP config files. Laravel’s config loader only reads PHP, so the practical pattern is: keep Laravel’s core config/*.php files, and load TOML files into config or into dedicated services at runtime.

Install it and confirm your PHP/Laravel versions:

composer require internal/toml

Laravel 10/11 on PHP 8.1+ is the natural target. Laravel 9 projects still on PHP 8.0 cannot use it.

First look at the public API in the README:

use Internal\Toml\Toml;

Toml::parse(string $toml): Document;        // AST, format-preserving
Toml::parseToArray(string $toml): array;    // values only
Toml::encode(array|JsonSerializable $data): Stringable;

A good first use case is a service-specific TOML file that is too nested for .env but does not belong in Laravel’s core config tree. Put it somewhere explicit, e.g. config/toml/services.toml or resources/toml/services.toml, then load it in a provider:

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Internal\Toml\Toml;

class TomlConfigServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $path = base_path('config/toml/services.toml');

        if (! is_file($path)) {
            return;
        }

        try {
            $data = Toml::parseToArray(file_get_contents($path));
        } catch (\Throwable $e) {
            throw new \RuntimeException("Invalid TOML config: {$path}", 0, $e);
        }

        config(['toml.services' => $data]);
    }
}

Register the provider, then read values with normal Laravel config access:

config('toml.services.database.host');
config('toml.services.features.beta');

This gives you a working read path in minutes. Before rolling it out broadly, add tests around the files you parse and decide whether TOML values need schema validation beyond TOML syntax validation.

Implementation Patterns

1. Wrap TOML in a small config repository instead of scattering Toml::parseToArray() calls.

A dedicated class gives you one place for caching, validation, error messages, and test seams:

namespace App\Support;

use Illuminate\Support\Facades\Cache;
use Internal\Toml\Toml;

class TomlConfig
{
    public static function load(string $path): array
    {
        $key = 'toml-config:' . $path . ':' . filemtime($path);

        return Cache::rememberForever($key, function () use ($path) {
            return Toml::parseToArray(file_get_contents($path));
        });
    }
}

Invalidate on deploy, or key the cache by file hash/mtime. This avoids parsing the same TOML file on every request or Octane worker boot.

2. Use TOML for domain configuration, not Laravel bootstrap configuration.

Good candidates:

  • Per-service settings: queue names, retry policies, endpoint maps.
  • Feature flags and experiment rules with nested tables.
  • Tenant-specific settings loaded by a request-scoped service.
  • Generated infrastructure templates for CI/CD or local tooling.
  • Test fixtures where readable nested data matters.

Avoid putting TOML directly in config/ and expecting config:cache to pick it up. Laravel’s config cache only serializes PHP config. If you need TOML values inside the cached config, generate a PHP config file from TOML during deployment.

3. Generate TOML from PHP for CLI commands and exports.

The encoder is useful for Artisan commands that produce configuration files:

use Illuminate\Support\Facades\File;
use Internal\Toml\Toml;

$toml = (string) Toml::encode([
    'database' => [
        'host' => 'localhost',
        'port' => 5432,
    ],
    'servers' => [
        ['name' => 'alpha', 'ip' => '10.0.0.1'],
        ['name' => 'beta', 'ip' => '10.0.0.2'],
    ],
]);

File::put(storage_path('app/generated/config.toml'), $toml);

This is the strongest day-to-day use case: PHP has the data, TOML is the human-readable output format. The encoder emits TOML 1.0-compatible output for interoperability, even though the parser supports TOML 1.1.

4. Use the AST when comments and formatting matter.

Toml::parseToArray() and Toml::encode() are a values-only round trip. Comments, hex formatting, and original layout are lost. If you are editing a TOML file in place and need to preserve comments, parse to a Document and serialize it back:

$document = Toml::parse($originalToml);

// Mutate nodes as needed. The README documents Entry, Table,
// and TableArray node types under $document->nodes.

$updatedToml = (string) $document;

The README demonstrates format preservation with magic = 0xDEADBEEF: parsing and re-serializing the untouched document keeps the hex form. For surgical edits, inspect $document->nodes and mutate the relevant node. If the AST API is too low-level for your use case, fall back to toArray() + encode() and accept formatting loss. Add tests before relying on AST mutation in production.

5. Encode DTOs with JsonSerializable and use DateTimeImmutable for TOML datetimes.

The encoder accepts arrays or JsonSerializable. A config DTO is a clean boundary:

final class ServiceConfig implements JsonSerializable
{
    public function __construct(
        public string $name,
        public DateTimeImmutable $createdAt,
    ) {}

    public function jsonSerialize(): array
    {
        return [
            'name' => $this->name,
            'created_at' => $this->createdAt,
        ];
    }
}

DateTimeImmutable values encode as TOML datetimes. When parsing, expect date/time values to come back as DateTimeImmutable; verify timezone behavior for local date/time values in your tests.

6. Validate schema after parsing.

TOML syntax validation is not schema validation. Parse first, then validate with Laravel’s validator or a dedicated schema:

$data = Toml::parseToArray(file_get_contents($path));

$validated = validator($data, [
    'database.host' => ['required', 'string'],
    'database.port' => ['required', 'integer', 'between:1,65535'],
    'features' => ['array'],
])->validate();

For CI, also lint TOML files with a dedicated tool such as taplo or toml-validator. That catches syntax problems before the application boots.

7. Test TOML files as fixtures and test encode/parse idempotence.

Put fixture files under tests/Fixtures/toml/ and assert parsed arrays:

$data = Toml::parseToArray(file_get_contents(base_path('tests/Fixtures/toml/services.toml')));

$this->assertSame('localhost', $data['database']['host']);

For generated TOML, encode then parse again:

$toml = (string) Toml::encode($payload);
$this->assertSame($payload, Toml::parseToArray($toml));

This catches unsupported values, nulls, and array/table shape mismatches early.

8. Integrate with package publishing when distributing TOML defaults.

If you ship a package with default TOML files, publish them explicitly:

$this->publishes([
    __DIR__ . '/../resources/toml' => config_path('toml'),
], 'toml-config');

Then read from config_path('toml/...') in your provider. This keeps TOML out of Laravel’s PHP config loader while still giving users a conventional location.

Gotchas and Tips

  • Laravel’s config:cache does not cache TOML. A provider that calls Toml::parseToArray() runs after cached PHP config is loaded, so it still works, but it reads the TOML file at runtime. Cache the parsed array yourself or generate PHP config during deployment if you need everything inside Laravel’s config cache.

  • TOML has no null. Remove or normalize nulls before calling Toml::encode(). Recursively filter nulls or convert them to an explicit sentinel value. Test empty arrays and empty tables too: TOML cannot represent every PHP array shape identically, especially an “empty array of tables.”

  • Only arrays, scalars, and JsonSerializable objects are safe to encode. Convert Eloquent models, Collection instances, and arbitrary objects explicitly with ->toArray() or a DTO. Don’t rely on accidental JsonSerializable behavior for domain objects.

  • parseToArray() + encode() loses comments and formatting. If you need comment preservation, hex number preservation, or exact layout, use Toml::parse() and serialize the Document. If you only need values, parseToArray() is simpler and faster.

  • The encoder targets TOML 1.0 output even though the parser supports 1.1. TOML 1.1-only syntax may be normalized or downgraded when encoded. If exact 1.1 syntax matters, keep the source TOML as the source of truth and avoid an encode step, or test the output carefully.

  • Pin a recent 1.1.x release. Version 1.1.1 fixed duplicate key names in different table scopes, and 1.1.2 improved TOML 1.1 and bare-key parsing. If you are on 1.0.x, upgrade before relying on nested table keys:

    "internal/toml": "^1.1"
    
  • TOML keys are case-sensitive and dotted keys can collide with Laravel’s dot notation. If a TOML file contains a quoted key like "a.b", config('toml.a.b') will not find it. Access the array directly:

    $config = config('toml');
    $value = $config['a.b'];
    
  • Parse errors need context. The package throws on invalid TOML. Catch the exception at the file boundary and include the path in your own exception message. Don’t let a raw parser exception leak into an API response. For debugging, validate the file with taplo or toml-validator, or bisect by commenting out sections.

  • DateTime handling deserves tests. DateTimeImmutable encodes as a TOML datetime, but local date, local time, and offset datetime have different semantics in TOML. Verify how your parsed values round-trip, especially if you store timestamps without timezones.

  • Large integers are 64-bit TOML integers. PHP on 64-bit platforms is fine, but 32-bit PHP deployments can overflow. Laravel deployments are usually 64-bit, but check if you encode IDs or large counters.

  • Octane and tenant-specific TOML need request-scoped state. If you load tenant TOML into config() inside a provider, that value can persist in the worker. Prefer a request-scoped service or explicitly reset tenant config per request. Use the cache-backed repository pattern for shared TOML files.

  • The package is small and low-traffic. Five stars and zero dependents is not a reason to reject it, but it is a reason to isolate it behind an adapter, pin versions, and test the TOML shapes you rely on. The API surface is tiny (parse, parseToArray, encode), so replacing it later is straightforward if needed.

  • No documented extension points. There is no plugin system or custom encoder hook. If you need inline tables, exact dotted-key output, or custom formatting, you will likely need AST manipulation or a different tool. For most Laravel use cases, the default encoder output is sufficient; confirm with a fixture test before shipping generated files.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums