# Generic

---

## Overview

Upload any file to Fly Registry and organize it by package name and version. Generic storage works with any file type -- you choose a package name and version, and Fly stores your files under that path.

---

## How It Works

Generic storage organizes files by **package name** and **version**:

| Concept | What it is | Example |
|---------|-----------|---------|
| **Package name** | A name that groups related files | `my-app`, `ml-models`, `config-bundle` |
| **Version** | An identifier for a specific set of files | `1.0.0`, `latest`, `nightly-2025-03-18` |
| **Files** | One or more files stored under that package and version | `app.dmg`, `checksums.txt` |

A file's full path in Fly Registry is:

`<your-fly-subdomain>.jfrog.io/artifactory/api/generic/<name>/<version>/<filename>`

Use generic storage for anything that doesn't go through a package manager: release binaries, build outputs, signed archives, configuration bundles, or any file your team needs to share and version.

### Parameters

| Parameter | Required | Description |
|-----------|----------|-------------|
| `--name` | Yes | Package name to group your files under |
| `--version` | Yes | Version label for this set of files |
| `--exclude` | No | Wildcard pattern to skip matching files (can be used multiple times) |
| `--output-dir` | No | Directory to save downloaded files to (download only) |

Files are listed at the end of the command. You can specify one or more file paths, or use wildcards like `*.zip`.

---

## Upload Package

### With Fly App

Ask your coding agent:

*"Upload my release files to Fly under my-app version 1.0.0"*

Or use the terminal directly -- Fly App handles authentication automatically:

```bash
fly upload --name my-app --version 1.0.0 dist/app.dmg
```

Upload multiple files or use wildcards:

```bash
# Multiple files or wildcards
fly upload --name my-app --version 1.0.0 release/*.zip build/**/*.bin

# Skip specific files
fly upload --name my-app --version 1.0.0 --exclude '*.log' release/*
```

### With an Access Token

To upload without Fly App authentication, use an access token with cURL:

```bash
curl -u <your-fly-username>:<your-fly-token> \
  -T my-file.bin \
  https://<your-fly-subdomain>.jfrog.io/artifactory/api/generic/my-app/1.0.0/my-file.bin
```

---

## Download Package

### With Fly App

Ask your coding agent:

*"Download my-app version 1.0.0 from Fly"*

Or use the terminal directly:

```bash
fly download --name my-app --version 1.0.0 app.dmg
```

Download multiple files to a specific folder:

```bash
fly download --name my-app --version 1.0.0 --output-dir ./release file1.zip file2.tar.gz
```

> [!NOTE]
> Unlike upload, download expects exact filenames -- glob patterns are not expanded.

### With an Access Token

To download without Fly App authentication, use an access token with cURL:

```bash
curl -u <your-fly-username>:<your-fly-token> \
  -O https://<your-fly-subdomain>.jfrog.io/artifactory/api/generic/my-app/1.0.0/my-file.bin
```

---

## Upload Package with CI

Ask your coding agent: **"Add my app (generic package) version 1.0.0 to my workflow"** -- Fly will configure it for you.

**1. Add permissions** (top level, after `on:`):
```yaml
permissions:
  contents: read
  id-token: write
```

**2. Add Fly Action and upload step** (in your job's `steps:`):
```yaml
- uses: jfrog/fly-action@v1              # Setup Fly package managers

- uses: jfrog/fly-action/upload@v1       # Upload artifacts
  with:
    name: my-app
    version: '1.0.0'
    files: |
      dist/*.zip
      dist/*.tar.gz
```

---

## Download Package with CI

**1. Add permissions** (top level, after `on:`):
```yaml
permissions:
  contents: read
  id-token: write
```

**2. Add Fly Action and download step** (in your job's `steps:`):
```yaml
- uses: jfrog/fly-action@v1              # Setup Fly package managers

- uses: jfrog/fly-action/download@v1     # Download artifacts
  with:
    name: my-app
    version: '1.0.0'
    files: |
      installer.dmg
      checksums.txt
    exclude: |                             # Skip files matching pattern
      *.log
    output-dir: ./release
```

---

## GitHub Action Example

A complete workflow with both upload and download:

```yaml
name: Release Artifacts

on:
  push:
    tags: ['v*']

permissions:
  contents: read
  id-token: write                        # Authentication

jobs:
  release:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - uses: jfrog/fly-action@v1              # Setup Fly package managers

      - uses: jfrog/fly-action/upload@v1       # Upload artifacts
        with:
          name: my-app
          version: ${{ github.ref_name }}
          files: |
            dist/*.zip
            dist/*.tar.gz

      - uses: jfrog/fly-action/download@v1     # Download artifacts
        with:
          name: my-app
          version: ${{ github.ref_name }}
          files: installer.dmg
          output-dir: ./release
```

---

## Verify Results

After each upload or download, you can verify your files were transferred successfully. The action outputs a summary for each file:

```yaml
- name: Upload artifacts
  id: upload
  uses: jfrog/fly-action/upload@v1
  with:
    name: my-app
    version: '1.0.0'
    files: dist/*.zip

- name: Check results
  run: echo '${{ steps.upload.outputs.results }}'
  # [{"name":"app.zip","status":"success","message":"..."}]
```

---

*Back to [Package Managers →](../)*
