---
title: "Configuration — Reviews for Laravel | Roundly"
description: "Every config key and its default — models, key type, rating scale, moderation, aggregates, API resources and review photos."
url: https://roundly-consulting.com/open-source/docs/reviews-for-laravel/configuration
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Reviews for Laravel](https://roundly-consulting.com/open-source/docs/reviews-for-laravel.md)

# Configuration

The package works with zero configuration. The published config/reviews.php in full:

```php
<?php

use RoundlyConsulting\Reviews\Enums\ReviewStatus;
use RoundlyConsulting\Reviews\Http\Resources\ReviewableResource;
use RoundlyConsulting\Reviews\Http\Resources\ReviewAuthorResource;
use RoundlyConsulting\Reviews\Models\Review;
use RoundlyConsulting\Reviews\Models\ReviewVote;
use RoundlyConsulting\Reviews\Moderation\NullModerator;

return [
    'model' => Review::class,
    'vote_model' => ReviewVote::class,

    'key_type' => env('REVIEWS_KEY_TYPE', 'bigint'),

    'min_rating' => env('REVIEWS_MIN_RATING', 1),
    'max_rating' => env('REVIEWS_MAX_RATING', 5),

    'default_status' => ReviewStatus::Pending->value,
    'auto_approve' => env('REVIEWS_AUTO_APPROVE', false),
    'reset_status_on_edit' => env('REVIEWS_RESET_STATUS_ON_EDIT', true),
    'one_per_author' => env('REVIEWS_ONE_PER_AUTHOR', false),

    'register_facade_alias' => env('REVIEWS_REGISTER_FACADE_ALIAS', true),

    'moderator' => NullModerator::class,
    'moderation' => [
        'banned_words' => array_values(array_filter(array_map(
            'trim',
            explode(',', (string) env('REVIEWS_BANNED_WORDS', '')),
        ))),
    ],

    'cache_aggregates' => env('REVIEWS_CACHE_AGGREGATES', false),

    'resources' => [
        'author' => ReviewAuthorResource::class,
        'reviewable' => ReviewableResource::class,
    ],

    'photos' => [
        'enabled' => env('REVIEWS_PHOTOS_ENABLED', true),
        'bucket' => env('REVIEWS_PHOTOS_BUCKET', 'photos'),
        'disk' => env('REVIEWS_PHOTOS_DISK'),
        'private_disk' => env('REVIEWS_PHOTOS_PRIVATE_DISK', 'local'),
        'max' => env('REVIEWS_PHOTOS_MAX', 5),
        'max_file_size' => env('REVIEWS_PHOTOS_MAX_FILE_SIZE', 5 * 1024 * 1024),
        'accepted_mime_types' => ['image/jpeg', 'image/png', 'image/webp', 'image/gif'],
        'responsive_widths' => [320, 640, 1024],
        'visibility' => env('REVIEWS_PHOTOS_VISIBILITY', 'public'),
        'warm_on_approval' => env('REVIEWS_PHOTOS_WARM_ON_APPROVAL', true),
    ],
];
```

## Every key

| Key | Default | Env | Purpose |
| --- | --- | --- | --- |
| `model` | Review::class | — | Review model; point it at your subclass to extend it. Any other class throws InvalidConfigurationException. |
| `vote_model` | ReviewVote::class | — | Helpful-vote model; point it at your subclass to extend it. Any other class throws InvalidConfigurationException. |
| `key_type` | bigint | `REVIEWS_KEY_TYPE` | Key type of the reviewable, author and voter morph columns — bigint, uuid or ulid (anything else throws InvalidConfigurationException). Read when the migrations run. |
| `min_rating` | 1 | `REVIEWS_MIN_RATING` | Lowest allowed rating, 0–255 (the rating column is an unsigned tinyint). |
| `max_rating` | 5 | `REVIEWS_MAX_RATING` | Highest allowed rating, from min\_rating (at least 1) to 255. |
| `default_status` | pending | — | Status a review lands in when the moderator leaves it undecided (and auto-approve is off). Any value that isn’t a ReviewStatus throws. |
| `auto_approve` | false | `REVIEWS_AUTO_APPROVE` | Approve new — and re-moderated, edited — reviews immediately, skipping the moderator. |
| `reset_status_on_edit` | true | `REVIEWS_RESET_STATUS_ON_EDIT` | On an edit to the rating, title or content, send an undecided review back to default\_status (false: keep its status). The moderator re-runs either way. |
| `one_per_author` | false | `REVIEWS_ONE_PER_AUTHOR` | Block a second non-deleted review by the same author for the same subject; owner responses don’t count. Re-checked with a locking read under the author’s row lock. |
| `register_facade_alias` | true | `REVIEWS_REGISTER_FACADE_ALIAS` | Register the global Reviews alias; any other string is used as the alias name. false/0/off/no (or an explicit null) skip it; a blank value is not set, so the alias is registered. |
| `moderator` | NullModerator::class | — | ReviewModerator consulted on create and on edits to the rating, title or content; swap in WordListModerator or your own. A class that doesn’t implement ReviewModerator throws. |
| `moderation.banned_words` | \[\] | `REVIEWS_BANNED_WORDS` | Comma-separated words the WordListModerator rejects on. Set in PHP, it must be a list of non-empty strings. An entry with a space or punctuation (rip off, f\*ck) matches as consecutive words; one with no word in it is ignored. |
| `cache_aggregates` | false | `REVIEWS_CACHE_AGGREGATES` | Keep cached reviews\_count / reviews\_avg in sync on opted-in reviewables. |
| `resources.author` | ReviewAuthorResource::class | — | The JsonResource a review’s author renders through in ReviewResource. It receives the author model; swap it for your own to add a name or an avatar — see JSON resource. |
| `resources.reviewable` | ReviewableResource::class | — | The JsonResource a review’s subject renders through, the same way. |
| `photos.enabled` | true | `REVIEWS_PHOTOS_ENABLED` | Master switch for review photos; when false the bucket is never declared and withPhoto() throws. |
| `photos.bucket` | photos | `REVIEWS_PHOTOS_BUCKET` | The media bucket photos are stored in (a string; blank = not set → photos). |
| `photos.disk` | null | `REVIEWS_PHOTOS_DISK` | Disk for every photo. Not set (null or blank) = by visibility: private → photos.private\_disk, public → media-library’s default disk. |
| `photos.private_disk` | local | `REVIEWS_PHOTOS_PRIVATE_DISK` | Non-public disk for private photos and their variants when photos.disk is not set (a string; blank = not set → local). |
| `photos.max` | 5 | `REVIEWS_PHOTOS_MAX` | Per-review photo limit, at least 0 (0 = unlimited, only when set explicitly); overflow throws tooManyPhotos(). |
| `photos.max_file_size` | 5242880 | `REVIEWS_PHOTOS_MAX_FILE_SIZE` | Largest accepted upload, in bytes (5 MB), at least 0 (0 = no per-photo cap, only when set explicitly). |
| `photos.accepted_mime_types` | jpeg, png, webp, gif | — | Allowed image mime types (\[\] accepts any type). |
| `photos.responsive_widths` | \[320, 640, 1024\] | — | Responsive width ladder of positive integers (null uses the media-library default). |
| `photos.visibility` | public | `REVIEWS_PHOTOS_VISIBILITY` | public or private (exact, lowercase); anything else throws rather than publishing the photos. |
| `photos.warm_on_approval` | true | `REVIEWS_PHOTOS_WARM_ON_APPROVAL` | Queue variant generation when a review is approved. |

Every bool switch is read strictly: true/1/on/yes turn it on, false/0/off/no turn it off, a blank value (REVIEWS\_PHOTOS\_ENABLED=) is not set so the default applies, and anything else (say REVIEWS\_PHOTOS\_ENABLED=disabled) throws InvalidConfigurationException instead of quietly reading as the default.

Every other setting is read just as strictly. A setting that is not set — absent, null, or blank like a host’s REVIEWS\_PHOTOS\_DISK= — takes its default (photos.disk stays unset). Integers accept an int or a plain integer string (“10”, as every env value is a string); five, 5.5 or 1e3 throws rather than becoming 0 — which for photos.max would have meant unlimited photos. A photos.visibility typo such as privat throws rather than making the photos public, and a non-string bucket or disk name, a non-list mime-type or width setting, or a junk entry in one throws too. A resources.\* value that is not a concrete JsonResource subclass — a model class, JsonResource itself, an abstract or missing class — throws InvalidConfigurationException naming the key on the first render.

## Environment

Most switches are env-driven, so you rarely need to publish the file at all:

```bash
REVIEWS_MIN_RATING=1
REVIEWS_MAX_RATING=10
REVIEWS_AUTO_APPROVE=false
REVIEWS_ONE_PER_AUTHOR=true
REVIEWS_BANNED_WORDS=spam,scam
REVIEWS_CACHE_AGGREGATES=true
REVIEWS_PHOTOS_MAX=3
REVIEWS_PHOTOS_VISIBILITY=private
```

REVIEWS\_BANNED\_WORDS is split on commas and trimmed, so spaces around the words are harmless.

## Inspecting the live configuration

The package adds a Reviews section to Laravel’s about command — models, rating scale, moderation switches, aggregates and photo settings:

```bash
php artisan about --only=reviews
```

It reports switches, bounds and presence only: the banned-word list appears as a count and the photo disk as SET or DEFAULT, so the output is safe to paste into a ticket. A broken rating scale, default status, banned-word list or photo setting renders as INVALID instead of failing the command.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/reviews-for-laravel.md)
