# scssphp: an SCSS compiler that runs inside your PHP process

> scssphp is a PHP implementation of the SCSS compiler, published on Packagist under an MIT licence, with a test suite that compiles every input file and compares it against a stored output, plus a bridge to the upstream sass-spec test corpus. It suits a PHP project that has to compile Sass as part of a build step and does not want a separate Node or Ruby toolchain, and the honest caveat is that the upstream compatibility test suite is opt-in and the static analysis runs against a baseline of known errors.

**scssphp/scssphp** — SCSS compiler written in PHP

- Repository: https://github.com/scssphp/scssphp
- Website: https://scssphp.github.io/scssphp/
- Stars: 629 · Forks: 90
- Language: PHP
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/scssphp-scssphp

## Why a Sass compiler in PHP at all

scssphp is a compiler for SCSS written in PHP, and the project describes it in exactly those terms, with a link to its homepage at scssphp.github.io/scssphp for directions on how to use it.

The reason such a thing exists is straightforward. Sass is the standard stylesheet language for the web, and the reference implementations are Ruby and Dart, which means a PHP project that wants to compile Sass has to add a second toolchain to its build, with its own version pinning, its own container image and its own install step. A PHP implementation of the compiler removes that step, at the price of being a reimplementation rather than the reference.

That price is visible throughout the project, and the README is honest about it rather than glossing over it. The test suite has a file called `FailingTest.php` whose stated purpose is to contain tests reported in GitHub issues that demonstrate compatibility bugs. In other words, the project keeps a running list of the places where its behaviour diverges from what the reference implementation does, as executable tests rather than as prose in an issue tracker.

The package is published on Packagist as scssphp, MIT licensed, with the site at scssphp.github.io/scssphp. The primary language is PHP, and the topic tags are sass, scss, php and hacktoberfest, which says the project takes outside contributions.

The release history shows a stable 2.x line: v2.1.0 from 2025-11-21, v2.0.1 from 2025-01-31 and v2.0.0 from 2024-12-23, with the last push on 2026-09-15.

The repository layout is a normal PHP library: a `bin/` directory for the command line entry point, `src/` for the source, `tests/` for the test suite, `docs/` for the documentation, a `composer.json`, a `Makefile` and a `MAINTENANCE.md`.

## Five test files that say what the project actually checks

The test suite is the most informative part of the README, because it describes what the project guarantees and, more usefully, what it does not.

Tests are run with PHPUnit, and the full suite is run from the root directory with:

```
    vendor/bin/phpunit tests
```

There are several test files in the `tests/` directory and each has a distinct job.

`ApiTest.php` contains various unit tests that test the PHP interface. `ExceptionTest.php` contains unit tests that test for exceptions thrown by the parser and compiler. `FailingTest.php` contains tests reported in Github issues that demonstrate compatibility bugs, which as noted is the project's register of known divergences from the reference behaviour.

`InputTest.php` is the interesting one. It compiles every `.scss` file in the `tests/inputs` directory and then compares it to the respective `.css` file in the `tests/outputs` directory. That is a golden file test over a corpus of inputs, and it means the repository carries both the inputs and the expected outputs, so a change in compiler behaviour shows up as a diff in a committed artefact.

`SassSpecTest.php` extracts tests from the `sass/sass-spec` repository, which is the upstream specification test suite. And this one is opt-in, because running it requires an environment variable to be set:

```
    TEST_SASS_SPEC=1 vendor/bin/phpunit tests
```

That is the honest limitation of the project stated in its own documentation. The full compatibility corpus exists and can be run, but it is not part of the default test run, so a green default test run does not mean full upstream compatibility.

There is also a mechanism for regenerating the golden outputs, which is essential to work with a golden file suite:

```
    BUILD=1 vendor/bin/phpunit tests
```

This will compile all the tests and save results into `tests/outputs`, and it also updates the list of excluded specs from sass-spec. The README warns that when changing any of the tests in `tests/inputs` the tests will most likely fail because the output has changed, and that you should verify the output is correct before rebuilding. The distinction between a compiler change and a test change is therefore a human judgement, not something the suite can decide for you.

## PSR-12, phpstan and a baseline of ignored errors

The code quality setup is where you can see how a long-lived PHP project handles the fact that most of its code predates modern static analysis.

The source conforms to PSR12, and the check runs with phpcs:

```
    vendor/bin/phpcs --standard=PSR12 --extensions=php bin src tests
```

Static analysis uses phpstan, and the README gives the command as:

```
    make phpstan
```

The interesting part is the next paragraph. As most of the codebase is composed of legacy code which cannot be type-checked fully, the setup contains a baseline file with all errors we want to ignore. In particular, all errors related to not specifying the types inside arrays are ignored, when these arrays correspond to the representation of Sass values and Sass AST nodes in the parser and compiler.

That is a precise and defensible scope for the baseline. The untyped arrays are the AST and the value representation, which are the parts of a compiler that are most awkward to type in PHP, and blanketing the whole project in a baseline would have made the tool useless. What it means in practice is that phpstan is enforced everywhere except the core data structures.

The contribution process for the baseline is documented, and it is the part that keeps a baseline from becoming a rug to sweep errors under. When contributing, the proper process is: make the change, run `make phpstan`, fix errors reported by phpstan when possible, repeat until nothing gets fixed anymore, and then run `make phpstan-baseline` to regenerate the baseline.

And then the important sentence: additions to the baseline will be reviewed to avoid ignoring errors that should have been fixed. So the baseline is a reviewed artefact rather than a free pass, and a contributor cannot quietly enlarge it.

The Makefile backs all of this up with a target per operation, `test`, `sass-spec`, `rebuild-sass-spec`, `rebuild-outputs`, `standard`, `fix-cs`, `phpstan`, `phpstan-verbose` and `phpstan-baseline`, each depending on a `vendor` target that runs `composer update` and touches a stamp file. The `fix-cs` target uses phpcbf to apply coding standard fixes automatically, and the `sass-spec` target pipes the full compatibility run through tee and tail so you get the last two lines of a very long log.

There is also a `phpcs.xml.dist` and a `phpstan.neon` alongside the `phpstan-baseline.neon`, so the rules are all in the repository rather than in a developer's global config.

## What the Makefile reveals about the development loop

The Makefile at the repository root is short, and it reads as a description of how a contributor actually works.

Almost every target depends on a `vendor` target, which depends on `composer.json` and runs `composer update` followed by a `touch` on the stamp file. So the dependency tools are installed on demand rather than being a prerequisite, and any change to the composer manifest invalidates them.

```bash
test: vendor
	vendor/bin/phpunit --colors tests
```

The `test` target runs the whole suite with colours, and there is a separate `sass-spec` target that runs the same suite with the environment variable set, piping the output through `tee /tmp/sass-spec.log` and `tail -2`. That pipeline is a practical detail rather than a stylistic one. The sass-spec corpus produces a great deal of output, and taking the last two lines gives you the summary while the log file keeps the detail for when you need it.

The rebuild targets are separated by what they rebuild. `rebuild-sass-spec` runs the sass-spec test file with `BUILD=1` set, and `rebuild-outputs` runs the input test file with `BUILD=1` set. Keeping them apart matters because they write to different places, the first updating the excluded spec list and the second writing the golden CSS files.

The coding standard targets come in a pair. `standard` runs phpcs with the `-s` flag, which prints the sniff codes as well as the messages, and `fix-cs` runs phpcbf to apply the fixes automatically. The `-s` flag is the difference between a report you can search and a report you have to read.

There is a `phpstan-verbose` target next to `phpstan`, and both run the same analyse command with and without the `-v` flag. The verbose mode is what you need when the baseline makes a result confusing, because it shows which errors are being suppressed.

The `.PHONY` line at the bottom lists all nine targets, which is the correct thing to do since none of them produce a file named after the target.

## Against the Dart Sass binary and against a PHP port with a different scope

The comparison worth making is with the reference implementations, because the choice between them is a real trade rather than a preference.

The first option is running the official Dart Sass compiler, usually through npm, as a step in your build. That gives you exactly the reference behaviour, it is what the sass-spec corpus is written against, and it is what almost every tutorial assumes. The cost is a second toolchain in the pipeline, a Node dependency to pin and keep current, and the possibility that a frontend build system and a PHP build step disagree about which Sass version is in use, which is a genuinely confusing class of bug.

The second option is what scssphp offers. The compiler runs in the same process as the rest of your PHP tooling, so there is no second runtime to install, and a library that consumes a PHP package manager can consume this one too. That is the whole argument, and it is a strong one for a project whose entire build is already PHP.

What you give up is fidelity. A reimplementation of a language is a permanent maintenance obligation, because the language moves. The upstream Sass team ships features and fix bugs and the reimplementation has to follow, and the `FailingTest.php` file is the visible ledger of where it currently does not. The opt-in sass-spec suite is the tool you would use to find out, and it is not part of the default test run.

There is a third path worth naming, which is not to compile at all. Modern CSS has features that a lot of Sass was used to work around, and a project that only needs nesting and custom properties may not need a preprocessor at all, in which case the entire question is settled by a build step you already have. The comparison to make in that case is not between PHP and Dart Sass but between a preprocessor and no preprocessor.

The honest summary is that scssphp earns its place when the alternative is a second toolchain, and the diligence it asks of you is running the full sass-spec suite periodically rather than trusting the default test run.

## Conclusion

Adopt scssphp if your build is already PHP and you would rather compile Sass in process than add a Node or Ruby toolchain to your pipeline. Do not adopt it expecting a drop-in replacement for the reference Sass implementation, because the compatibility test suite that would prove that is opt-in and must be run separately, and check first that your Sass features are covered, since the compiler is a reimplementation and the project tracks known compatibility bugs in a dedicated test file.

## FAQ

### What is scssphp?

It is a compiler for SCSS written in PHP, published on Packagist as scssphp under an MIT licence, with a homepage at scssphp.github.io/scssphp for usage directions. The project is written in PHP and its topic tags include sass, scss, php and hacktoberfest.

### How do I run the scssphp test suite?

With PHPUnit, from the root directory: `vendor/bin/phpunit tests`. The `tests/` directory holds `ApiTest.php` for the PHP interface, `ExceptionTest.php` for parser and compiler exceptions, `FailingTest.php` for known compatibility bugs from GitHub issues, `InputTest.php` which compiles every file in `tests/inputs` and compares with `tests/outputs`, and `SassSpecTest.php` for the upstream sass-spec corpus.

### How do I run the full sass-spec compatibility tests?

You have to enable them explicitly with `TEST_SASS_SPEC=1 vendor/bin/phpunit tests`. The upstream sass-spec corpus is not part of the default test run, so a green default run does not mean full upstream compatibility.

### How do I rebuild the expected test outputs after a compiler change?

Run `BUILD=1 vendor/bin/phpunit tests`, which compiles all the tests, saves the results into `tests/outputs` and updates the list of excluded sass-spec specs. The README warns that changing an input will most likely fail the tests, so you should verify the new output is correct before rebuilding.

### What coding standard and static analysis does scssphp use?

The source conforms to PSR12, checked with `vendor/bin/phpcs --standard=PSR12 --extensions=php bin src tests`, and static analysis uses phpstan run through `make phpstan`. Because much of the codebase is legacy and cannot be fully type-checked, there is a baseline file of ignored errors, and additions to it are reviewed.

### Is scssphp still being maintained?

The repository is not archived and the last push was on 2026-09-15. Recent releases are v2.1.0 from 2025-11-21, v2.0.1 from 2025-01-31 and v2.0.0 from 2024-12-23, and the project is MIT licensed.

## Sources

- [License: MIT](https://github.com/scssphp/scssphp/blob/main/LICENSE)
- [Project website](https://scssphp.github.io/scssphp/)
- [README](https://github.com/scssphp/scssphp/blob/main/README.md)
- [Releases](https://github.com/scssphp/scssphp/releases)
- [scssphp/scssphp on GitHub](https://github.com/scssphp/scssphp)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/scssphp-scssphp
