<@ULVA73B9P> does prefect support storing and serv...
# ask-marvin
d
@Marvin does prefect support storing and serving a downloadable file as the result of a flow_run? I'm creating a JSON blob as the result of a flow run and I'd like to make it easily downloadable.
m
thought for 450.7 seconds
Short answer: Prefect won’t host your file for download, but you can make it easily downloadable from the UI by uploading the JSON to object storage (e.g., S3/GCS/Azure) and attaching a link artifact to the flow run. Users can then click the artifact to download. Two common patterns - Small JSON for quick viewing - Create a markdown artifact with the JSON inline so it’s visible on the run page. - Downloadable file (recommended) - Upload the JSON to your storage of choice and create a link artifact pointing to it. For private buckets, generate a short-lived signed URL. Example: upload JSON to S3 and add a clickable download link
Copy code
from __future__ import annotations

import json
import tempfile
from prefect import flow, task
from prefect.artifacts import create_link_artifact
from prefect_aws.s3 import S3Bucket, get_s3_client


@task
def build_json() -> dict:
    # Your result here
    return {"status": "ok", "items": [1, 2, 3]}


@task
def upload_json_to_s3(data: dict, s3_block_name: str, key: str, expires_seconds: int = 3600) -> str:
    # Save to a temp file
    with tempfile.NamedTemporaryFile("w", suffix=".json", delete=False) as f:
        json.dump(data, f)
        f.flush()
        tmp_path = f.name

    # Upload using a Prefect block
    bucket = S3Bucket.load(s3_block_name)
    bucket.upload_from_path(from_path=tmp_path, to_path=key)

    # Generate a presigned URL for download
    s3 = get_s3_client()
    url = s3.generate_presigned_url(
        "get_object",
        Params={"Bucket": bucket.bucket_name, "Key": key},
        ExpiresIn=expires_seconds,
    )
    return url


@flow
def create_downloadable_result(s3_block_name: str = "my-s3-bucket-block"):
    data = build_json()
    key = "reports/my_result.json"
    url = upload_json_to_s3(data, s3_block_name, key)

    # Create a clickable artifact on the flow run page
    create_link_artifact(
        key="flow-output-json",
        link=url,
        link_text="Download JSON result",
        description="Flow output as a JSON file"
    )

    return data  # Optional: you can still return the dict as the flow result


if __name__ == "__main__":
    create_downloadable_result()
Notes - If you prefer GCS or Azure, use the corresponding Prefect block to upload and create a signed URL, then create a link artifact the same way. - You can also persist the flow’s return value using Prefect’s result storage, but for a user-friendly “download” experience in the UI, link artifacts are the best approach. - For very small JSON, you can make it visible inline:
Copy code
from prefect.artifacts import create_markdown_artifact
  create_markdown_artifact(markdown=f"```json\n{json.dumps(data, indent=2)}\n```")
Docs - Artifacts overview and how-to: Artifacts concepts and Create artifacts - AWS S3 integration: prefect-aws and S3 reference S3Bucket - GCP GCS integration: prefect-gcp and GCS reference GcsBucket Question for you - Which storage backend do you use (S3/GCS/Azure/local)? Do you need public links or expiring signed URLs? I can tailor the snippet accordingly.