¿Qué es Firebase Storage?
Firebase Cloud Storage es un servicio de almacenamiento de objetos potente, simple y rentable construido a escala de Google. Te permite almacenar y servir contenido generado por usuarios, como fotos, videos y otros archivos. Firebase Storage está respaldado por Google Cloud Storage y ofrece cargas y descargas seguras para tus apps de Firebase.
Con Firebase Storage puedes subir archivos directamente desde el cliente sin necesidad de tu propio servidor, y los archivos se almacenan en un bucket de Google Cloud Storage.
📦 Características clave
- 🔒 Seguro: Las reglas de seguridad protegen tus archivos.
- 📈 Escalable: Escala automáticamente para cualquier volumen de datos.
- 🌐 Con CDN: Archivos servidos desde una CDN global para entrega rápida.
- 📱 Soporte offline: Maneja automáticamente interrupciones de red.
- ⏸️ Reanudable: Cargas y descargas pueden pausarse y reanudarse.
Configurar Firebase Storage
Inicializa Storage en tu aplicación:
import { initializeApp } from 'firebase/app';
import { getStorage } from 'firebase/storage';
const firebaseConfig = {
// Your config here
storageBucket: 'your-project.appspot.com'
};
const app = initializeApp(firebaseConfig);
const storage = getStorage(app);
export { storage };
Estructura de Storage
Los archivos se organizan en una estructura jerárquica similar a un sistema de archivos:
// Storage bucket structure
gs://your-bucket/
├── users/
│ ├── user1/
│ │ ├── avatar.jpg
│ │ └── documents/
│ │ └── resume.pdf
│ └── user2/
│ └── avatar.png
├── posts/
│ ├── post1/
│ │ ├── image1.jpg
│ │ └── image2.jpg
│ └── post2/
│ └── cover.jpg
└── public/
└── logo.png
Subir archivos
Sube archivos desde diferentes fuentes:
Subir desde input de archivo
import { ref, uploadBytes, getDownloadURL } from 'firebase/storage';
async function uploadFile(file, path) {
// Create a reference to the file location
const storageRef = ref(storage, path);
// Upload the file
const snapshot = await uploadBytes(storageRef, file);
console.log('Uploaded file:', snapshot.metadata.name);
// Get the download URL
const downloadURL = await getDownloadURL(snapshot.ref);
return downloadURL;
}
// Usage with file input
const fileInput = document.getElementById('file-input');
fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
const url = await uploadFile(file, `uploads/${file.name}`);
console.log('File available at:', url);
});
Subir con seguimiento de progreso
import { ref, uploadBytesResumable, getDownloadURL } from 'firebase/storage';
function uploadFileWithProgress(file, path, onProgress) {
const storageRef = ref(storage, path);
const uploadTask = uploadBytesResumable(storageRef, file);
return new Promise((resolve, reject) => {
uploadTask.on('state_changed',
(snapshot) => {
// Track progress
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
onProgress(progress);
switch (snapshot.state) {
case 'paused':
console.log('Upload paused');
break;
case 'running':
console.log('Upload running');
break;
}
},
(error) => {
// Handle errors
reject(error);
},
async () => {
// Upload completed
const downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
resolve(downloadURL);
}
);
});
}
// Usage
const url = await uploadFileWithProgress(file, 'images/photo.jpg', (progress) => {
console.log(`Upload is ${progress}% done`);
});
Subir desde string (Base64, Data URL)
import { ref, uploadString, getDownloadURL } from 'firebase/storage';
// Upload base64 encoded string
async function uploadBase64(base64String, path) {
const storageRef = ref(storage, path);
const snapshot = await uploadString(storageRef, base64String, 'base64');
return getDownloadURL(snapshot.ref);
}
// Upload data URL (e.g., from canvas)
async function uploadDataURL(dataURL, path) {
const storageRef = ref(storage, path);
const snapshot = await uploadString(storageRef, dataURL, 'data_url');
return getDownloadURL(snapshot.ref);
}
// Upload from canvas
const canvas = document.getElementById('myCanvas');
const dataURL = canvas.toDataURL('image/png');
const url = await uploadDataURL(dataURL, 'images/drawing.png');
Agregar metadatos
Adjunta metadatos personalizados a los archivos:
import { ref, uploadBytes, updateMetadata } from 'firebase/storage';
// Upload with metadata
async function uploadWithMetadata(file, path, customMetadata) {
const storageRef = ref(storage, path);
const metadata = {
contentType: file.type,
customMetadata: {
uploadedBy: customMetadata.userId,
description: customMetadata.description,
originalName: file.name
}
};
const snapshot = await uploadBytes(storageRef, file, metadata);
return snapshot;
}
// Update metadata after upload
async function updateFileMetadata(path, newMetadata) {
const storageRef = ref(storage, path);
const updatedMetadata = await updateMetadata(storageRef, {
customMetadata: newMetadata
});
return updatedMetadata;
}
Descargar archivos
Obtén URLs de descarga y descarga archivos:
import { ref, getDownloadURL, getBlob, getBytes } from 'firebase/storage';
// Get download URL
async function getFileURL(path) {
const storageRef = ref(storage, path);
const url = await getDownloadURL(storageRef);
return url;
}
// Download as Blob (for files up to memory limit)
async function downloadAsBlob(path) {
const storageRef = ref(storage, path);
const blob = await getBlob(storageRef);
return blob;
}
// Download as bytes
async function downloadAsBytes(path) {
const storageRef = ref(storage, path);
const bytes = await getBytes(storageRef);
return bytes;
}
// Usage: Display image
const url = await getFileURL('images/photo.jpg');
document.getElementById('image').src = url;
Eliminar archivos
Elimina archivos del almacenamiento:
import { ref, deleteObject } from 'firebase/storage';
async function deleteFile(path) {
const storageRef = ref(storage, path);
try {
await deleteObject(storageRef);
console.log('File deleted successfully');
} catch (error) {
if (error.code === 'storage/object-not-found') {
console.log('File does not exist');
} else {
throw error;
}
}
}
// Delete user's avatar
await deleteFile('users/user123/avatar.jpg');
Listar archivos
Lista archivos en un directorio:
import { ref, listAll, list } from 'firebase/storage';
// List all files in a folder
async function listAllFiles(path) {
const storageRef = ref(storage, path);
const result = await listAll(storageRef);
// Process items (files)
const files = await Promise.all(
result.items.map(async (item) => ({
name: item.name,
fullPath: item.fullPath,
url: await getDownloadURL(item)
}))
);
// Process prefixes (folders)
const folders = result.prefixes.map((folder) => ({
name: folder.name,
fullPath: folder.fullPath
}));
return { files, folders };
}
// Paginated listing (for large directories)
async function listFilesPaginated(path, maxResults = 10, pageToken = null) {
const storageRef = ref(storage, path);
const options = { maxResults };
if (pageToken) {
options.pageToken = pageToken;
}
const result = await list(storageRef, options);
return {
files: result.items,
folders: result.prefixes,
nextPageToken: result.nextPageToken // Use for next page
};
}
Componente de carga de archivos en React
Crea un componente reutilizable para subir archivos:
import { useState } from 'react';
import { ref, uploadBytesResumable, getDownloadURL } from 'firebase/storage';
import { storage } from '../lib/firebase';
export function FileUpload({ onUploadComplete, path = 'uploads' }) {
const [progress, setProgress] = useState(0);
const [uploading, setUploading] = useState(false);
const [error, setError] = useState(null);
const handleFileChange = async (e) => {
const file = e.target.files[0];
if (!file) return;
setUploading(true);
setError(null);
const fileName = `${Date.now()}-${file.name}`;
const storageRef = ref(storage, `${path}/${fileName}`);
const uploadTask = uploadBytesResumable(storageRef, file);
uploadTask.on('state_changed',
(snapshot) => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
setProgress(progress);
},
(error) => {
setError(error.message);
setUploading(false);
},
async () => {
const downloadURL = await getDownloadURL(uploadTask.snapshot.ref);
setUploading(false);
setProgress(0);
onUploadComplete({ url: downloadURL, name: fileName });
}
);
};
return (
<div>
<input type="file" onChange={handleFileChange} disabled={uploading} />
{uploading && (
<div>
<progress value={progress} max="100" />
<span>{Math.round(progress)}%</span>
</div>
)}
{error && <p className="text-red-500">{error}</p>}
</div>
);
}
// Usage
function ProfilePage() {
const handleUpload = ({ url, name }) => {
console.log('Uploaded:', url);
// Save URL to user profile in database
};
return <FileUpload onUploadComplete={handleUpload} path="avatars" />;
}
Redimensionar imagen antes de subir
Redimensiona imágenes en el cliente antes de subirlas:
async function resizeImage(file, maxWidth, maxHeight) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = (e) => {
const img = new Image();
img.onload = () => {
const canvas = document.createElement('canvas');
let width = img.width;
let height = img.height;
// Calculate new dimensions
if (width > height) {
if (width > maxWidth) {
height *= maxWidth / width;
width = maxWidth;
}
} else {
if (height > maxHeight) {
width *= maxHeight / height;
height = maxHeight;
}
}
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, width, height);
canvas.toBlob(resolve, 'image/jpeg', 0.8);
};
img.src = e.target.result;
};
reader.readAsDataURL(file);
});
}
// Usage
async function uploadResizedImage(file, path) {
const resizedBlob = await resizeImage(file, 800, 600);
const storageRef = ref(storage, path);
const snapshot = await uploadBytes(storageRef, resizedBlob);
return getDownloadURL(snapshot.ref);
}
💡 Puntos clave
- • Firebase Storage guarda archivos en buckets de Google Cloud Storage
- • Usa uploadBytes para subidas simples y uploadBytesResumable para progreso
- • Obtén URLs con getDownloadURL para servir archivos
- • Agrega metadatos personalizados para organizar y buscar archivos
- • Redimensiona imágenes en cliente para ahorrar ancho de banda y almacenamiento
- • Usa reglas de seguridad para proteger el acceso a archivos
📚 Más recursos
-
Documentación de Cloud Storage →
Guías oficiales y APIs de Firebase Storage
-
Guía para subir archivos →
Guía detallada para subir archivos a Storage
-
Reglas de seguridad de Storage →
Asegura tus archivos con reglas de almacenamiento