- How do I install spatie/simple-excel in a Laravel application?
- Install it with a single command: composer require spatie/simple-excel. There is no service provider, config file, migration, or published asset to deal with, so nothing needs registering in your app. Because the package depends on illuminate/support, it is already aligned with a standard Laravel install. You can have a working import or export in about five lines of code.
- Does spatie/simple-excel use a lot of memory when reading large Excel files?
- No, memory usage stays flat regardless of file size. Reading is built on generators, and getRows() returns an Illuminate\Support\LazyCollection, so rows are streamed one at a time instead of being loaded into an array. Calling each() or chunking through the LazyCollection processes millions of rows without exhausting memory. This is the main reason to choose it over loading a whole sheet into a Collection.
- What file formats does spatie/simple-excel support?
- Only .csv and .xlsx, and the format is auto-detected from the file extension passed to SimpleExcelReader::create() or SimpleExcelWriter::create(). There is no .xls or .ods path in the documented reader and writer factories, and no multi-sheet writing story. It is also not a formatting engine, so charts, pivot tables, and cell styling are out of scope. If you need those, reach for the underlying OpenSpout package or PhpSpreadsheet directly.
- Why is my written xlsx file empty or only partially written?
- Writes are finalized lazily: an .xlsx file does not get flushed to disk until the writer instance is garbage collected. In long-running workers, Laravel Octane, or queued jobs where the object stays referenced, that can silently produce an empty or truncated file. Call close() explicitly, ideally in a finally block, as a mandatory coding convention. Also be aware there is no atomicity: a crash or timeout mid-write leaves a corrupt file that still looks valid by name, so write to a temp path and rename if that matters.
- How do I convert imported headers to snake_case or skip the header row?
- The package ships a header toolkit that removes most import boilerplate: trimHeaderRow(), headersToSnakeCase(), formatHeadersUsing(), headerOnRow(), useHeaders(), and noHeaderRow(). There are matching value helpers, trimValues() and formatValuesUsing(), for cleaning cell contents. Combined, these replace the manual array mapping most teams hand-roll around fgetcsv. Note that duplicate header names collapse silently into a single key, with no warning.
- Can I stream an Excel or CSV download from a Laravel controller?
- Yes, the writer exposes a streamDownload() method that maps onto Laravel's StreamedResponse. Rows are pushed to the browser as they are generated, so the file never has to be buffered to disk first. That makes it a good fit for large exports and memory-constrained containers. Remember to keep the response generation inside the streaming callback so LazyCollection semantics are preserved.
- Why are dates or leading zeros wrong when reading an xlsx file?
- Type coercion is silent and depends on both the source cell format and the file type. Date cells come back as DateTimeImmutable by default, and you opt into formatted strings with preserveDateTimeFormatting(). Numeric cells in .xlsx arrive as PHP numbers, so an identifier like 007123 loses its leading zeros unless the column is text-formatted in the source. CSVs are string-oriented, so the same data as .xlsx and as .csv can yield different PHP types, meaning any schema contract must be defined per format.
- Can I use spatie/simple-excel outside of Laravel?
- Technically yes, but it is not clean. The package has a hard dependency on illuminate/support because getRows() returns an Illuminate\Support\LazyCollection, so a non-Laravel service would have to pull in the Collections package. Inside a Laravel codebase that same dependency is a strength: first-class fit, generator-backed iteration, and constant memory. If you are building framework-agnostic code, use openspout or PhpSpreadsheet directly instead.
- Is it safe to read Excel files uploaded by users with this package?
- The package documents nothing about hardening untrusted input, so treat that responsibility as yours. An .xlsx is a ZIP of XML, which means decompression-bomb and entity-expansion risks are inherited from the parsing layer upstream. Enforce upload size limits, memory_limit, max_execution_time, and temp-disk capacity at the application level before the reader ever touches the file. Validate the detected extension yourself rather than trusting the client-supplied filename.
- Can I drop down to OpenSpout if the wrapper does not cover my use case?
- Yes, getReader() exposes the underlying OpenSpout\Reader\ReaderInterface, so the facade is not a ceiling. Anything the fluent API does not handle, such as less common reader options, can be done directly against OpenSpout on the same object. That escape hatch significantly lowers lock-in risk. Just keep in mind the package is a thin ergonomic adapter, not an Excel engine, so the underlying library's limits apply.