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

Nova Audio Laravel Package

davidpiesse/nova-audio

A Laravel Nova field for working with audio files. It provides an easy way to upload, store, and preview audio in Nova resources, with a built-in player for listening to uploaded tracks directly from the admin panel. Ideal for podcasts, music, voice notes, and other audio content.

View on GitHub
Deep Wiki
Context7

Getting Started

Confirm the ground you're standing on before writing a line of code. This field only exists inside Laravel Nova. Check composer show laravel/nova first — if you're on Nova 4 or 5, stop and read the Gotchas section before you invest an afternoon.

composer require davidpiesse/nova-audio

Wire up the minimum viable field in a resource you actually use:

use Davidpiesse\NovaAudio\Audio;

public function fields(Request $request)
{
    return [
        ID::make()->sortable(),
        Text::make('Title'),
        Audio::make('Track', 'track')
            ->disk('public')
            ->path('audio/tracks')
            ->rules('required', 'file', 'mimes:mp3,wav,ogg', 'max:51200'),
    ];
}

Add a string column (or text if paths get long) to the migration, php artisan migrate, and php artisan storage:link if the disk is public.

Where to look first in the source. The package is tiny — read the PHP Field class and the Vue component before your first commit. Three questions to answer from that reading: (1) what column does the upload write to, and is it the path or just the filename? (2) does it build a public Storage::url() or a temporary/signed URL? (3) does it enforce any validation at all, or does it defer entirely to your ->rules(). Everything else is Nova boilerplate you already know from File.

Your first use case: prove the loop on a throwaway branch. Pick the simplest resource in your admin — a PodcastEpisode, a LessonAudio, a VoicePrompt — upload one real MP3 through the UI, confirm the row contains the filename, and confirm the <audio> element renders on both the detail view and the index. That fifteen minutes tells you more about Nova-version compatibility and disk behaviour than an hour of reading source. Do it before you add it to a sprint plan.

Implementation Patterns

Treat it as a filename column with a player bolted on. The real contract is: upload a file to a disk, write a path into a normal Eloquent string attribute. That column is yours to use anywhere — Storage::disk($disk)->url($episode->track) in a Blade view, a queued transcription job, an export. The package is a form control, not an owner of the audio. Internalising that makes every downstream decision easier.

Centralise storage policy in a project field class. Don't sprinkle ->disk()->path() through twenty resources. Define one subclass that fixes your defaults:

namespace App\Nova\Fields;

use Davidpiesse\NovaAudio\Audio;

class TrackAudio extends Audio
{
    public function __construct($name, $attribute = null, $resolveCallback = null)
    {
        parent::__construct($name, $attribute ?? $name, $resolveCallback);

        $this->disk(config('media.audio_disk'))
             ->path('audio/'.now()->format('Y/m'))
             ->rules('file', 'mimes:mp3,wav,ogg', 'max:51200');
    }
}

Now the disk, path layout, and MIME allowlist live in one place. When you move from public to a CDN-fronted S3 bucket, that's a config change plus a path re-point — not a grep-and-replace across the Nova directory.

Always pair it with server-side validation. The package will not reliably enforce MIME or size for you. This is one line and it's the most important hardening step:

->rules('required', 'file', 'mimes:mp3,wav,ogg', 'max:51200')  // max is in KB → 50MB

Match max to your upload_max_filesize / post_max_size / Nginx client_max_body_size, or the browser gets an opaque 413 before your rule ever runs.

Pattern: the preview-before-publish workflow. This is the package's sweet spot. Editor uploads → inline player renders immediately → editor listens → corrects or publishes. Put the audio field on the same form as the publish toggle, and use ->hideWhenCreating() / ->hideWhenUpdating() if audio is mandatory only on update (e.g. a second-pass review step).

Pattern: keep the disk swappable from day one. Audio is the dominant storage and egress cost in nearly every app that has it. Because the field only stores a path string, switching public → signed-URL S3 is genuinely a config change — but only if nobody hardcoded Storage::disk('public') elsewhere. Enforce that in review.

Integration tip: one field per record, and stop there. The package handles a single file cleanly. If product asks for multi-file, ordering, waveforms, or duration extraction, don't bend this field — reach for Spatie Media Library plus a custom Nova field. That's a different project, not a different config.

Use the stored path outside Nova immediately. A useful day-two exercise: add a duration accessor or a small AudioController that streams the file, reading $model->track and config('media.audio_disk'). It proves the field is a thin UI over your own storage, and it gives you the seam where signed URLs or transcoding will eventually live.

Gotchas and Tips

Nova version is the whole ballgame. Last release was April 2020 — Nova 2/3 era. Nova 4 reworked the field/frontend layer; Nova 5 moved further. A 2020-vintage Vue 2 component is not expected to mount cleanly on Nova 4+. If you're on 4 or 5, budget a port or a rebuild — not an integration. Spike it in a timebox before you commit to it in a sprint.

Pin it exactly, and fail loudly in CI. composer require davidpiesse/nova-audio with no constraint will float, and there's no upstream to fix anything. Pin the tag or commit in composer.json, and add a CI job that boots Nova with the field registered. The classic failure mode: a Nova upgrade breaks the field's JS, admins see a blank input, uploads silently stop, and nobody notices for a week.

Verify the URL strategy before planning private audio. Does the field build a plain Storage::url() or a temporary/signed URL? If it's the former, any file on a private disk will 403 in the player. For internal-only or regulated audio you need short-lived signed URLs, which likely means overriding resolve/preview or wrapping the field. Check the source — don't assume.

Never trust the extension. Add a server-side MIME allowlist via ->rules(). Don't rely on what the browser claims. One line, highest-value hardening you'll do.

Upload limits fail opaquely. Audio hits upload_max_filesize, post_max_size, and Nginx client_max_body_size fast. When exceeded, users get a 413 with no useful message. Set all three deliberately, document the ceiling, and surface it as field help text: "MP3/WAV/OGG up to 50MB." Don't let an editor discover the limit by losing a 30MB recording.

Orphaned files are your problem. Deleting a record doesn't delete the audio file, and there's nothing in the package to do it for you. Add a model observer on deleted, or a scheduled sweep for files with no owning row. Audio files are large; orphans are expensive.

Codec mismatch beats everything. The package accepts MP3/WAV/OGG, but browsers don't uniformly play all of these — WAV plays but is enormous, OGG is spotty on Safari. If playback correctness matters, normalise to MP3/AAC on upload (an ffmpeg job, out of scope for this field), or restrict accepted input to a format you know plays everywhere you care about.

No metadata, no accessibility. No duration extraction, no waveform, no caption/transcript association, and no keyboard controls beyond what the native <audio> element provides. If the admin UI is ever shown to a client, or the audio is health/education/call-recording data, those obligations are yours.

Vendor it if you keep it. Zero dependents, 22 stars, one maintainer, no release in five years — there's no support safety net. If you adopt it, copy the source into nova-components/ (or an internal namespace), pin the commit, and own the tests. Budget roughly one day per Nova major upgrade. If that stewardship cost is unattractive, the alternative — a native File field plus a small bespoke player component, scaffolded with nova:field — is two to three engineer-days and removes the third-party surface entirely.

Extension point: the Vue component. Any real customisation — waveform rendering, duration display, a different player UI, signed-URL refresh on expiry — happens by forking the Vue component, not by configuration. Plan for that from the start if the product wants anything beyond upload-and-play.

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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route