Загрузка и обслуживание изображений в Supabase Storage для Next.js
О чём статья
Это пошаговое руководство объясняет, как настроить проект Supabase и bucket для хранения изображений, как инициализировать supabase-js в Next.js, как сделать форму загрузки и как безопасно выдавать загруженные файлы в приложении. Дополнительно указаны альтернативы, критерии приёмки, чеклисты ролей, советы по безопасности и тесты.
Создание проекта Supabase
Если у вас ещё нет приложения Next.js, начните с официального руководства Next.js, чтобы создать его.
Дальше создайте проект Supabase:
- Зайдите на сайт Supabase и зарегистрируйтесь или войдите в аккаунт.
- В панели Supabase нажмите “Create a new project”.
- Укажите имя проекта и нажмите “Create project”. После создания вы попадёте в панель управления проекта.
После создания проекта нужно добавить storage bucket.
Создание storage bucket в Supabase
Bucket — это место для файлов: изображений, видео и других статических активов. Его можно создать через Dashboard или через API/клиент.
Через Dashboard:
- Откройте страницу Storage в Dashboard.
- Нажмите “New Bucket” и задайте имя, например images.
- Нажмите “Create Bucket”.
Далее настроим клиент Supabase в приложении.
Настройка Supabase клиента
Установите клиентскую библиотеку supabase-js:
npm install @supabase/supabase-js
В корне приложения создайте папку lib (или используйте src/lib). В ней создайте файл supabase.js и инициализируйте клиент:
import { createClient } from '@supabase/supabase-js'
export const supabase = createClient('', '')
Рекомендуется хранить значения в переменных окружения. В .env добавьте:
SUPABASE_PROJECT_URL="your_project_url"
SUPABASE_PROJECT_ANON_KEY="your_project_anon_key"
И в supabase.js используйте переменные окружения:
export const supabase = createClient(
process.env.SUPABASE_PROJECT_URL,
process.env.SUPABASE_ANON_KEY
);
Теперь создадим страницу с формой для приёма файлов.
Создание формы для загрузки изображений
В Next.js (app router) создайте папку upload и файл page.js — это сделает маршрут /upload. Для Next.js 12 используйте pages/upload.js.
Пример компонента с формой (React client component):
"use client";
import { useState } from "react";
export default function Page() {
const [file, setfile] = useState([]);
const handleSubmit = async (e) => {
e.preventDefault();
// upload image
};
const handleFileSelected = (e) => {
setfile(e.target.files[0]);
};
return (
);
}
Когда вы выберете файл и отправите форму, вызовется handleSubmit — именно в нём будет логика загрузки.
Для больших форм с валидацией разумно рассмотреть библиотеки типа Formik или React Hook Form.
Загрузка файла в Supabase Storage
Внутри handleSubmit используйте клиент Supabase для загрузки в bucket. Примерный код:
const handleSubmit = async (e) => {
e.preventDefault();
const filename = `${uuidv4()}-${file.name}`;
const { data, error } = await supabase.storage
.from("images")
.upload(filename, file, {
cacheControl: "3600",
upsert: false,
});
const filepath = data.path;
// save filepath in database
};
Здесь мы создаём уникальное имя файла с помощью UUID, чтобы избежать перезаписывания файлов с одинаковыми именами.
Установите пакет uuid:
npm install uuid
Импортируйте UUID вверху страницы:
import { v4 as uuidv4 } from "uuid";Не забудьте импортировать supabase клиент:
import { supabase } from "@/lib/supabase";
Путь к файлу в bucket ведёт себя как файловая система: если у вас есть папка public в bucket, укажите “/public/filename”.
После успешной загрузки Supabase вернёт объект data, в котором находится путь к файлу (data.path). Сохраните этот путь в вашей базе данных (Postgres), чтобы позже связывать файл с сущностью (пользователь, пост и т.д.).
Политики доступа для загрузки
Для работы загрузки нужно добавить политику, разрешающую INSERT и SELECT к Storage (если вы используете Row Level Security и хотите разрешить доступ приложению):
- В Dashboard проекта откройте Storage.
- Выберите ваш bucket и вкладку Access.
- В разделе Bucket policies нажмите New policy.
- Выберите For full customization.
- Дайте имя политике, например Allow Insert and Read.
- Установите Allowed operations: INSERT и SELECT.
- Нажмите Review и затем Save.
После этого вы не должны получать ошибки доступа при загрузке.
Отдача (serve) загруженных изображений в приложении
Чтобы показать изображение в приложении, вам нужен публичный URL. Его можно получить двумя способами.
- Через supabase-js:
const filepath = "path_to_file_in_bucket"
const { data } = supabase
.storage
.from('images')
.getPublicUrl(`${filepath}`)
- Сконструировать URL вручную, объединяя базовый URL bucket и путь к файлу:
const filepath = `${bucket_url}/${filepath}`
Далее используйте компонент Image из Next.js:
Если вы используете приватные файлы, вместо getPublicUrl используйте .createSignedUrl для временных ссылок.
Когда такой подход не подходит
- Когда вам требуется мгновенное финальное CDN-кеширование со сложными правилами — стоит интегрировать CDN (Cloudflare/KeyCDN) или использовать S3/GCS с CDN.
- Если объём изображений очень большой и нужна многоуровневая обработка (трансформация изображений на лету) — рассмотрите специализированные сервисы (ImageKit, Cloudinary).
- Для критичных по задержке задач (стриминг, live-обновления) возможно понадобятся другие архитектурные решения.
Альтернативные подходы
- Хранить файлы в S3 (AWS) или GCS (Google Cloud Storage) и использовать тот же принцип: генерировать уникальные имена, хранить путь в базе, отдавать публичные или подписанные URL.
- Использовать CDN с origin на Supabase или S3 для ускорения отдачи.
- Использовать специализированные сервисы изображений для автоматических ресайзов и оптимизации.
Модель мышления и эвристики при выборе
- Если нужно просто хранить и отдавать файлы — Supabase Storage подходит по цене и интеграции.
- Если нужна глобальная низкая задержка и масштабируемость — используйте CDN на верхнем слое.
- Если нужна обработка изображений (ресайз, форматы WebP/AVIF) — используйте сервис с этими возможностями или добавьте обработку на сервере/edge.
Мини‑методология внедрения (пошагово)
- Создать проект Supabase и bucket images.
- Настроить переменные окружения и инициализировать supabase-js.
- Сделать форму загрузки в Next.js и реализовать логику upload с уникальными именами.
- Сохранить путь к файлу в Postgres вместе с метаданными (owner, mime-type, created_at).
- Настроить политики доступа в Storage.
- Решить вопрос с публичностью/подписанными URL и CDN.
- Написать тесты и мониторинг.
Чеклист ролей при релизе
- Разработчик:
- Реализовал upload и сохранение пути в БД.
- Добавил обработку ошибок и валидировал тип/размер файла.
- DevOps:
- Настроил переменные окружения в окружении развертывания.
- Проверил политики доступа и резервное копирование.
- Продукт/PM:
- Утвердил требования к размерам и формату изображений.
- Решил вопрос с политикой хранения и срока хранения файлов.
Критерии приёмки
- Форма успешно загружает изображения в bucket images.
- В базе данных сохраняется корректный путь к файлу.
- Изображение отображается в Next.js через public URL или signed URL.
- Нельзя загрузить файлы превышающие ограничение по размеру (если задано).
- Политики доступа не позволяют неавторизованному доступу к приватным файлам.
Тестовые сценарии и приёмочные тесты
- Попытка загрузить допустимый файл — загрузка успешна и путь сохранён.
- Попытка загрузить файл с тем же именем — файл сохраняется под уникальным именем.
- Попытка загрузить файл запрещённого типа — загрузка отклоняется.
- Получение signed URL для приватного файла — URL работает в течение заданного времени.
Советы по безопасности и приватности
- Не храните секреты (anon key, service role key) в клиентском коде. anon key допустим для клиентского доступа, service role key только на сервере.
- Для приватных файлов используйте подписанные URL с ограниченным сроком жизни.
- Ограничьте типы и размеры файлов на стороне сервера/фронтенда.
- Логируйте ошибки загрузки и доступ к файлам для аудита.
- Учтите требования GDPR: храните только необходимые метаданные и давайте пользователям возможность удалять свои файлы.
Миграция и совместимость
- При переносе данных с файловой системы на Supabase/облако — экспортируйте файлы и сохраните новые пути в базе.
- Если вы используете Next.js Image Optimization, добавьте домен Supabase/ CDN в next.config.js domains.
Шпаргалка (cheat sheet)
- Уникальное имя:
${uuidv4()}-${file.name} - Загрузка: supabase.storage.from(‘images’).upload(path, file)
- Публичный URL: supabase.storage.from(‘images’).getPublicUrl(path)
- Подписанный URL (private): supabase.storage.from(‘images’).createSignedUrl(path, expiresInSeconds)
Факто‑бокс с ключевыми моментами
- Хранение в базе BLOB: дорого и не масштабируется.
- Supabase Storage: удобен для файлов и интеграции с Postgres.
- UUID: помогает избежать конфликтов имён.
- Signed URL: безопасный способ отдачи приватных файлов.
Пример объявления релиза (короткая версия)
В проект добавлена возможность загружать и хранить изображения в Supabase Storage. Реализована форма загрузки, сохранение пути в Postgres и отдача изображений через публичные или подписанные URL.
Социальный предпросмотр
OG title: “Supabase: загрузка изображений в Next.js” OG description: “Пошаговое руководство по загрузке и выдаче изображений через Supabase Storage и supabase-js для Next.js.”
Заключение
Хранение изображений в Supabase Storage — простой и масштабируемый способ для большинства веб-приложений. Это лучше, чем хранить BLOB в базе данных: меньше затрат, проще интеграция с CDN и безопасные ссылки. Планируйте обработку изображений и политику доступа заранее, тестируйте сценарии загрузки и доступа, и вы получите надёжную систему управления медиа.
Похожие материалы
Как хранить данные PS5 в облаке и освобождать место
Вход через соцсети в WordPress с Super Socializer
Как Firefox удаляет параметры запроса и защищает приватность
Как подключить Ring к Google Home
Дни отдыха после тренировок — план для восстановления