Skip to content
Back to skills

Frappe Core Files

ASecurity

Use when handling file uploads, attachments, private/public file access, or S3 storage configuration. Prevents broken file URLs, permission leaks on private files, and failed uploads from incorrect MIME handling. Covers File DocType, frappe.get_file, upload API, private vs public directories, S3 integration, file URL patterns, attach field types. Keywords: file, upload, attachment, File DocType, private, public, S3, file_url, get_file, attach, upload not working, file missing, broken file lin...

  • 174 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 6, 2026
ai-agentspythongobashapidatabasebackend

Works with

  • claude code
  • api

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned September 6, 2026

npx -y skills add OpenAEC-Foundation/ERPNext_Anthropic_Claude_Development_Skill_Package --skill frappe-core-files --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Frappe Core Files?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Frappe Core Files
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/openaec-foundation-frappe-core-files/badge)](https://www.skillsdirectory.com/skills/openaec-foundation-frappe-core-files)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: frappe-core-files
description: >
  Use when handling file uploads, attachments, private/public file access, or S3 storage configuration.
  Prevents broken file URLs, permission leaks on private files, and failed uploads from incorrect MIME handling.
  Covers File DocType, frappe.get_file, upload API, private vs public directories, S3 integration, file URL patterns, attach field types.
  Keywords: file, upload, attachment, File DocType, private, public, S3, file_url, get_file, attach, upload not working, file missing, broken file link, download file, image not showing, attachment error..
license: MIT
compatibility: "Claude Code, Claude.ai Projects, Claude API. Frappe v14-v16."
metadata:
  author: OpenAEC-Foundation
  version: "2.0"
---

# Frappe File Management

## Quick Reference

| Action | Method | Notes |
|--------|--------|-------|
| Save file from bytes | `save_file(fname, content, dt, dn)` | Returns File doc |
| Save file from URL | `save_url(file_url, fname, dt, dn)` | Creates File doc from URL |
| Read file content | `frappe.get_file(fname)` | Returns `[filename, content]` |
| Get file path | `get_file_path(file_name)` | Resolves to absolute path |
| Upload via HTTP | `POST /api/method/upload_file` | Multipart form upload |
| Delete file | `frappe.delete_doc("File", name)` | Removes doc + filesystem file |
| Attach print | `frappe.attach_print(dt, dn, print_format)` | Returns `{"fname", "fcontent"}` |
| Get cached doc | `frappe.get_cached_doc("File", name)` | Read-only, cached |

---

## Decision Tree

```
What file operation do you need?
│
├─ Upload a file from user input?
│  ├─ Via web form → Attach field type (auto-handles upload)
│  └─ Via API → POST /api/method/upload_file
│
├─ Create a file programmatically?
│  ├─ From bytes/content → save_file(fname, content, dt, dn)
│  ├─ From external URL → save_url(file_url, fname, dt, dn)
│  └─ Full control → frappe.get_doc({"doctype": "File", ...}).insert()
│
├─ Read file content?
│  ├─ By filename → frappe.get_file(fname)
│  └─ By File doc → file_doc.get_content()
│
├─ Public or private?
│  ├─ Public (anyone with link) → is_private=0, URL: /files/fname
│  └─ Private (permission-based) → is_private=1, URL: /private/files/fname
│
└─ Generate PDF attachment?
   └─ frappe.attach_print(doctype, name, print_format)
```

---

## File DocType: Core Fields

| Field | Type | Description |
|-------|------|-------------|
| `file_name` | Data | Filename without path |
| `file_url` | Data | URL path (e.g., `/files/report.pdf`) |
| `file_type` | Data | Extension (PDF, PNG, DOCX, etc.) |
| `is_private` | Check | 0 = public, 1 = private |
| `is_folder` | Check | True for folder entries |
| `folder` | Link → File | Parent folder |
| `attached_to_doctype` | Link → DocType | Parent document type |
| `attached_to_name` | Data | Parent document name |
| `attached_to_field` | Data | Field name on parent |
| `content_hash` | Data | SHA-256 for deduplication |
| `file_size` | Int | Size in bytes |

---

## File URL Patterns

| Type | URL Pattern | Filesystem Path |
|------|------------|-----------------|
| Public | `/files/{filename}` | `{site}/public/files/{filename}` |
| Private | `/private/files/{filename}` | `{site}/private/files/{filename}` |
| Remote | `https://...` | Not stored locally |
| API | `/api/method/{path}` | Generated dynamically |

Valid URL prefixes: `http://`, `https://`, `/api/method/`, `/files/`, `/private/files/`.

ALWAYS use `/private/files/` for sensitive documents. Public files are accessible to anyone with the URL, including unauthenticated users.

---

## Permission Model

Frappe files use a three-tier permission model:

1. **Administrator** — unrestricted access to all files
2. **Public files** (`is_private=0`) — readable by anyone with the URL (no authentication required for read)
3. **Private files** (`is_private=1`) — access requires:
   - User is the file owner, OR
   - User has explicit share on the file, OR
   - User has read permission on the `attached_to_doctype`/`attached_to_name` document

NEVER store sensitive data as public files. ALWAYS set `is_private=1` for documents containing personal data, financial records, or confidential information.

---

## Programmatic File Operations

### Save File from Content

```python
from frappe.utils.file_manager import save_file

# Save a generated CSV
csv_content = "Name,Amount\nACME,1000\nGlobex,2000"
file_doc = save_file(
    fname="report.csv",
    content=csv_content.encode("utf-8"),
    dt="Sales Invoice",           # attach to this DocType
    dn="SINV-00001",              # attach to this document
    folder="Home/Attachments",    # optional folder
    is_private=1,                 # private file
)
# file_doc.file_url → "/private/files/report.csv"
```

### Save File from URL

```python
from frappe.utils.file_manager import save_url

file_doc = save_url(
    file_url="https://example.com/logo.png",
    filename="company-logo.png",
    dt="Company",
    dn="My Company",
    folder="Home",
    is_private=0,
)
```

### Read File Content

```python
# By filename
filename, content = frappe.get_file("report.csv")

# By File document
file_doc = frappe.get_doc("File", {"file_name": "report.csv"})
content_bytes = file_doc.get_content()
```

### Create File Document Directly

```python
file_doc = frappe.get_doc({
    "doctype": "File",
    "file_name": "generated-report.pdf",
    "attached_to_doctype": "Sales Invoice",
    "attached_to_name": "SINV-00001",
    "is_private": 1,
    "content": pdf_bytes,  # raw bytes — written to disk on insert
}).insert(ignore_permissions=True)
```

### Generate and Attach PDF

```python
# Create PDF attachment dict (for use with sendmail)
pdf_attachment = frappe.attach_print(
    "Sales Invoice",
    "SINV-00001",
    print_format="Standard",
)
# Returns: {"fname": "Sales Invoice - SINV-00001.pdf", "fcontent": <bytes>}

# Save PDF as file attachment
from frappe.utils.file_manager import save_file

pdf = frappe.get_print("Sales Invoice", "SINV-00001", print_format="Standard", as_pdf=True)
save_file("invoice.pdf", pdf, "Sales Invoice", "SINV-00001", is_private=1)
```

---

## File Upload via REST API

```bash
# Upload file attached to a document
curl -X POST https://site.example.com/api/method/upload_file \
  -H "Authorization: token api_key:api_secret" \
  -F "file=@/path/to/document.pdf" \
  -F "doctype=Sales Invoice" \
  -F "docname=SINV-00001" \
  -F "is_private=1"
```

Response:
```json
{
  "message": {
    "name": "FILE-00001",
    "file_name": "document.pdf",
    "file_url": "/private/files/document.pdf",
    "is_private": 1
  }
}
```

---

## File Size and Extension Limits

**Default max file size:** 10 MB per attachment.

Override in `site_config.json`:
```json
{
  "max_file_size": 20971520
}
```

**Max attachments per document:** Set via Customize Form → Max Attachments field on the DocType.

**Check file size programmatically:**
```python
from frappe.utils.file_manager import check_max_file_size
check_max_file_size(content)  # raises MaxFileSizeReachedError if too large
```

---

## Attach Field Types

| Field Type | Stores | UI |
|------------|--------|----|
| `Attach` | Single file URL | File picker + upload button |
| `Attach Image` | Single image URL | Image preview + upload |

Both store the `file_url` string in the field value. The File DocType record is created separately with `attached_to_field` set.

---

## S3 / Cloud Storage Integration

Frappe supports custom file storage via the `delete_file_data_content` hook and custom upload handlers.

### S3 via frappe-s3-attachment or similar app

```python
# In hooks.py of custom app
delete_file_data_content = "my_app.storage.delete_from_s3"
```

ALWAYS test file deletion when using custom storage backends — the default `delete_file_from_filesystem` only handles local files.

### Configuration Pattern

```python
# site_config.json for S3-compatible storage
{
  "s3_bucket": "my-frappe-files",
  "s3_region": "eu-west-1",
  "s3_access_key": "AKIA...",
  "s3_secret_key": "...",
}
```

---

## Version Differences

| Feature | v14 | v15 | v16 |
|---------|-----|-----|-----|
| File DocType | Available | Available | Available |
| `content_hash` dedup | Available | Available | Available |
| Image optimization | Manual | Auto (1920x1080, 85%) | Auto |
| Import/Export Zip | Not available | Available | Available |

---

## See Also

- [references/examples.md](references/examples.md) — File operation code examples
- [references/anti-patterns.md](references/anti-patterns.md) — Common file handling mistakes
- `frappe-core-permissions` — Permission model for file access
- `frappe-core-database` — Database operations for File queries

Files in this skill

  • SKILL.md8.6 KB
  • references/anti-patterns.md4.4 KB
  • references/examples.md4.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.