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

Singlestore Laravel Laravel Package

singlestore/singlestore-laravel

Official SingleStore integration for Laravel, providing a native database driver with Eloquent and query builder support. Connect Laravel apps to SingleStore for fast distributed SQL, migrations, schema management, and familiar Laravel workflows.

View on GitHub
Deep Wiki
Context7

Getting Started

What you're getting. singlestore/singlestore-laravel is a first-party database driver that registers a singlestore connection driver with Laravel's DatabaseManager. Internally it subclasses Laravel's MySQL connection, query grammar, schema grammar, and post-processor, because SingleStoreDB speaks the MySQL wire protocol. Practically that means Eloquent models, the query builder, migrate, db:seed, and RefreshDatabase all work with almost no ceremony — but you are on a MySQL-shaped surface talking to a distributed HTAP engine, and that gap is where the real work lives.

Minimum steps.

  1. Enable the mysqli PHP extension. The driver connects via mysqli, not PDO, so a stock php:8.x-fpm image without docker-php-ext-install mysqli will fail at connect time with a confusing error.
  2. composer require singlestore/singlestore-laravel — the service provider is auto-discovered; there's nothing to publish.
  3. Add a connection block to config/database.php that mirrors your mysql block but changes the driver key:
'singlestore' => [
    'driver'    => 'singlestore',
    'host'      => env('SINGLESTORE_HOST', '127.0.0.1'),
    'port'      => env('SINGLESTORE_PORT', '3306'),
    'database'  => env('SINGLESTORE_DATABASE', 'app'),
    'username'  => env('SINGLESTORE_USERNAME', 'root'),
    'password'  => env('SINGLESTORE_PASSWORD', ''),
    'charset'   => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix'    => '',
    'strict'    => true,
    'engine'    => null,
],
  1. Point DB_CONNECTION=singlestore (or leave your primary alone and address it explicitly — see below).
  2. Verify with php artisan tinker → DB::connection('singlestore')->select('select now()'), then php artisan migrate.

Where to look first. Read the driver's source top-down: Connections/SingleStoreConnection, Connectors/SingleStoreConnector, Schema/Grammars/*, Query/Grammars/*. Each is a thin subclass of the corresponding Illuminate\Database\MySql* class, which tells you exactly how far MySQL fidelity goes and where it stops. When something behaves oddly, diff the driver class against the Laravel MySQL class it extends before opening a GitHub issue.

First real use case. The classic shape is a mixed workload: keep your transactional tables in rowstore (in-memory) form and put event/fact tables in columnstore, then let a few reporting endpoints or scheduled aggregates run against the same cluster. Start by pointing one read-heavy model or one DB::connection('singlestore') report at it rather than migrating the whole app on day one.

Implementation Patterns

Secondary connection, not replacement. Most teams I'd expect to run this as a second connection alongside MySQL/Postgres. Set it per-model with protected $connection = 'singlestore';, or ad hoc with Model::on('singlestore') / DB::connection('singlestore')->table(...). Eloquent relationships only work intra-connection, so treat "which data lives where" as a schema decision, not a query-time one.

Keep schema DDL explicit. The schema grammar is MySQL-derived, so $table->string(), indexes, and id() are fine, but SingleStore's defining features — SHARD KEY, SORT KEY, COLUMNSTORE, REFERENCE TABLE, ROWSTORE — are not first-class builder methods. Do them in raw statements inside migrations:

Schema::create('events', fn (Blueprint $t) => $t->bigIncrements('id')->...);
DB::statement('ALTER TABLE events ADD SHARD KEY (tenant_id)');
DB::statement('ALTER TABLE events ADD SORT KEY (created_at)');

Because ALTERs on SingleStore rewrite data, front-load these decisions in the initial create rather than bolting them on later.

Batch your writes. Columnstore tables want bulk inserts. Use DB::table('events')->insert($chunk) in slices of a few hundred to a few thousand rows, or LOAD DATA LOCAL INFILE for backfills, rather than looping Model::create(). Row-by-row Eloquent writes against a columnstore table is the single most common way to make this package look slow.

Choose table shape per table, per table's job. migrations, sessions, jobs, and small lookup tables → rowstore. High-volume append-only event/analytics tables → columnstore. Getting this inverted (a columnstore jobs table, say) produces transactional surprises rather than performance ones.

Use read/write keys deliberately. Laravel's split read/write config keys pass through, which is useful if you point reads at a different aggregator during heavy ingest, but on SingleStore both usually resolve to the same cluster. Don't assume splitting gets you much.

Test against a real node. SQLite will happily accept migrations the SingleStore grammar rejects. Run CI against the singlestoredb/singlestoredb-dev container with RefreshDatabase bound to the singlestore connection; the grammar/schema feedback loop is the main value.

Reporting queries. For window functions, CTEs, and JSON_* work, drop to DB::connection('singlestore')->select($sql, $bindings) rather than coaxing the builder. Keep those queries in dedicated repository classes so you can tune and explain them independently.

Gotchas and Tips

No PDO under the hood. The connection is mysqli-backed. Third-party packages that reach for $connection->getPdo() and call PDO-only methods (getAttribute, MYSQL_ATTR_LOCAL_INFILE, custom PDOStatement handling) are the most likely thing to break. Audit any package that does raw PDO work before adopting it here.

Transactions only exist on rowstore. Columnstore writes auto-commit. DB::transaction() wrapping columnstore inserts will appear to work and will not roll back on failure. Never rely on transactions for fact-table ingestion — make writes idempotent instead.

Foreign keys aren't enforced. ->foreignId()->constrained() emits the DDL but SingleStore does not enforce referential integrity. Treat FKs as documentation and enforce invariants in application code or via your ingest pipeline.

upsert() / updateOrCreate() semantics. ON DUPLICATE KEY UPDATE needs a unique key and behaves differently across table types; updateOrCreate is a read-then-write and is racy under concurrency. Test both explicitly, and check whether duplicates are silently collapsed by columnstore unique-key behavior.

lockForUpdate() / pessimistic locking. Meaningless or unsupported against columnstore, and the database queue driver (jobs table with FOR UPDATE) should stay on rowstore or move to Redis/SQS entirely. Same reasoning for Cache::store('database') and DB sessions.

strict => true may not stick. The MySQL connector issues SET SESSION sql_mode, and SingleStore's supported modes don't line up perfectly with MySQL's. If connection setup throws, flip 'strict' => false first — it's the usual culprit, and it's a config quirk, not a driver bug.

Idle connections get reaped. Long-running queue workers and scheduled reports will surface MySQL server has gone away. Raise wait_timeout if you control the cluster, and wrap long jobs with DB::reconnect('singlestore'). Persistent connections are not your friend here.

Long analytical queries hit PHP and proxy timeouts before the database's. Set explicit max_execution_time/statement timeouts in config, and be aware that an aggregator-side timeout looks like a generic query exception.

Schema introspection is expensive at scale. Schema::hasTable(), hasColumn(), and anything that hits information_schema on a large cluster is slower than on MySQL. migrate is fine; per-request introspection is not. Guard migrations so they aren't re-probing on every deploy.

Debugging toolkit. DB::listen(), ->dd()/->dump(), DB::enableQueryLog(), and Laravel Telescope all work normally through the driver — start there. EXPLAIN on SingleStore gives you shard/repartition info that has no MySQL equivalent; learn to read it before you start rewriting queries.

Extension points. You can DB::extend('singlestore', ...) with your own resolver, subclass the grammars to add builder methods for SHARD KEY/SORT KEY, or bind a custom connection class — all reasonable if you find yourself repeating raw DDL. There is no config file to publish, so connection tuning lives entirely in config/database.php.

Version discipline. The driver tracks Laravel majors closely and inherits from MySQL classes that change between minors. Pin it in composer.json and re-run the full migration suite whenever you bump Laravel; grammar inheritance failures are subtle and show up as malformed SQL, not exceptions.

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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core