Last modified: Oct 19, 2026
Upload Files to GCS with Python
Google Cloud Storage (GCS) is a durable and scalable object store. Python makes it easy to push files into a bucket programmatically.
This guide shows you how to upload files to GCS using the google-cloud-storage library. You will learn simple uploads, resumable uploads, and error handling.
Every example is beginner-friendly. You can copy the code and adapt it to your project right away.
Prerequisites
You need a Google Cloud project and a storage bucket. Create both in the Cloud Console before you start.
You also need a service account with the Storage Object Admin role. Download its JSON key file and keep it safe.
If you have not set up the library yet, follow a guide to install google-cloud-storage in Python inside a virtual environment.
Set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the key file path. The library reads it automatically.
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account-key.json"
Create a Storage Client
The client is your entry point to GCS. Create one instance and reuse it across your application.
Reusing the client avoids repeated authentication and connection setup. It also keeps memory usage low.
from google.cloud import storage
# Create a client using Application Default Credentials
client = storage.Client()
You can also pin a specific project if your credentials have access to many projects.
client = storage.Client(project="my-project-id")
Upload a File from Disk
The most common upload reads a file from your local disk. Use upload_from_filename() for this task.
This method streams the file and handles retries for transient network errors. It is the safest choice for large files.
from google.cloud import storage
def upload_from_disk(bucket_name, source_path, destination_blob_name):
"""Upload a local file to a GCS bucket."""
client = storage.Client()
bucket = client.bucket(bucket_name)
blob = bucket.blob(destination_blob_name)
# Upload the file from disk
blob.upload_from_filename(source_path)
print(f"Uploaded {source_path} to gs://{bucket_name}/{destination_blob_name}")
# Usage
upload_from_disk(
bucket_name="my-data-bucket",
source_path="./reports/monthly.pdf",
destination_blob_name="reports/2026/monthly.pdf",
)
Uploaded ./reports/monthly.pdf to gs://my-data-bucket/reports/2026/monthly.pdf
The method accepts an optional content_type argument. Set it when the file extension is ambiguous.
blob.upload_from_filename(
"data.bin",
content_type="application/octet-stream",
)
Upload from a File-Like Object
Sometimes you have an open file handle instead of a path. Use upload_from_file() for streams and in-memory buffers.
This is useful when you process data before uploading. You avoid writing a temporary file to disk.
import io
from google.cloud import storage
def upload_stream(bucket_name, blob_name, data: bytes):
"""Upload bytes from an in-memory buffer to GCS."""
client = storage.Client()
bucket = client.bucket(bucket_name)
blob = bucket.blob(blob_name)
# Wrap bytes in a file-like object
buffer = io.BytesIO(data)
blob.upload_from_file(buffer, content_type="text/plain")
print(f"Uploaded {len(data)} bytes to {blob_name}")
# Usage
upload_stream("my-data-bucket", "logs/app.log", b"INFO start\nINFO ready\n")
Uploaded 22 bytes to logs/app.log
Pass the correct content_type to keep the object readable in the Cloud Console and by browsers.
Upload a String or Bytes Directly
For small text or JSON payloads, use upload_from_string(). It is the simplest method for generated content.
Do not use it for large payloads. The entire value is held in memory during the upload.
import json
from google.cloud import storage
client = storage.Client()
bucket = client.bucket("my-data-bucket")
blob = bucket.blob("config/settings.json")
payload = json.dumps({"feature_flag": True, "version": 3}, indent=2)
# Upload a string directly
blob.upload_from_string(payload, content_type="application/json")
print("Config uploaded.")
Config uploaded.
This method is perfect for small configuration files and generated reports.
Use Resumable Uploads for Large Files
Large uploads can fail halfway. A resumable upload can continue after a network drop instead of starting over.
The high-level methods already use resumable uploads by default when the file exceeds a threshold. You can control the chunk size explicitly.
from google.cloud import storage
client = storage.Client()
bucket = client.bucket("my-data-bucket")
blob = bucket.blob("backups/database.sql.gz")
# Force a resumable upload with 8 MB chunks
blob.chunk_size = 8 * 1024 * 1024
blob.upload_from_filename(
"database.sql.gz",
content_type="application/gzip",
)
print("Large file uploaded with resumable transfer.")
Large file uploaded with resumable transfer.
Keep the chunk size between 256 KB and 100 MB. Larger chunks reduce overhead but use more memory per stream.
Handle Upload Errors Gracefully
Uploads can fail for many reasons. Permissions, network timeouts, and bucket policies are common causes.
Wrap uploads in a try/except block. Log the error and return a clear message to the caller.
from google.api_core.exceptions import Forbidden, NotFound, GoogleAPICallError
import sentry_sdk
def safe_upload(bucket_name, source_path, blob_name):
client = storage.Client()
blob = client.bucket(bucket_name).blob(blob_name)
try:
blob.upload_from_filename(source_path)
return True
except Forbidden:
print("Permission denied. Check the service account role.")
except NotFound:
print("Bucket does not exist.")
except GoogleAPICallError as exc:
print(f"Upload failed: {exc}")
sentry_sdk.capture_exception(exc)
return False
If you want centralized error tracking, install sentry-sdk in Python and capture upload failures automatically. This helps you spot permission drift before users notice.
The library also retries transient errors by default. You can customize the retry policy for stricter control.
from google.cloud.storage.retry import DEFAULT_RETRY
blob.upload_from_filename(
"data.csv",
retry=DEFAULT_RETRY,
timeout=300,
)
Best Practices for Reliable Uploads
Use clear and predictable blob names. Include dates, tenant IDs, or environment prefixes to avoid collisions.
Set the correct content_type on every upload. Browsers and downstream services rely on it.
Never hardcode bucket names. Read them from environment variables so staging and production stay separate.
Reuse the storage client across requests. Creating a client per upload wastes resources and slows down your application.
If uploads happen on a schedule, automate them. You can schedule Python tasks with Airflow and upload files as part of a reliable DAG.
Monitor upload failures with alerting. A silent failure in a backup job can go unnoticed for days.
Test your upload code with small files first. Then scale to large files and confirm the resumable path works.
Conclusion
Uploading files to GCS with Python is straightforward. Install the library, set up credentials, and create a storage client.
Use upload_from_filename() for disk files. Use upload_from_string() for small text. Use resumable uploads for large files.
Wrap uploads in error handling and log failures. That keeps your pipelines reliable and your data safe.
With these patterns, you can move files into Google Cloud Storage confidently from any Python application.