The .ics file format explained: VCALENDAR, VEVENT and what each line means
6 min read · Updated July 2026

Open any .ics file in a text editor and it is immediately readable: capitalised property names, a colon, a value. That legibility is deliberate. The iCalendar format was designed so a calendar entry could travel between programs written by people who never spoke to each other, and the price of that portability is a handful of strict rules. Once you know which lines are mandatory and what the punctuation is doing, you can read a calendar file at a glance, diagnose a failed import, and write one by hand when you have to.
A plain-text format with a standard behind it
The format is defined by RFC 5545, published in 2009 as a replacement for RFC 2445 from 1998. Files use the media type text/calendar and normally the .ics extension. The character encoding is UTF-8, and every line ends with a carriage return followed by a line feed — CRLF, not the bare newline that a Unix editor writes by default. Most clients tolerate bare newlines, but a few reject the file outright, which is a surprisingly common cause of "this file is not a valid calendar".
Everything is built from nested components, opened with BEGIN: and closed with END:. The outermost is always VCALENDAR. Inside it you may find VEVENT (an appointment), VTODO (a task), VJOURNAL (a note), VFREEBUSY (availability) and VTIMEZONE (the definition of a time zone). A typical file produced by a calendar app contains one VTIMEZONE and one or more VEVENT blocks, and nothing else.
Inside a component, each line is a property: a name, optional parameters separated by semicolons, a colon, then the value. DTSTART;TZID=Europe/Tallinn:20261005T090000 is the property DTSTART, with the parameter TZID set to Europe/Tallinn, and the value 5 October 2026 at 09:00 local time.
The wrapper: what VCALENDAR must carry
Only two properties are required on the calendar itself. VERSION:2.0 states which version of the specification the file follows — 2.0 has been the only answer since 1998. PRODID names the software that produced the file, in the form -//Company//Product//EN; it has no effect on behaviour, but it is what support teams look at first when a file misbehaves.
CALSCALE:GREGORIAN is the default and is usually written out anyway. METHOD matters more than it looks: METHOD:PUBLISH means "here is an event, add it if you like", while METHOD:REQUEST turns the same file into a meeting invitation and makes mail clients show Accept and Decline buttons. Sending a plain event with METHOD:REQUEST and no attendees confuses Outlook; sending an invitation with PUBLISH means nobody is asked to respond.
X-WR-CALNAME is not in the standard at all — it is an Apple extension from the early 2000s — yet nearly every client reads it, and it is what gives an imported calendar its name. RFC 7986 later standardised NAME for the same job, so a well-behaved file often carries both.
The event: the lines that must be there
A VEVENT needs a UID and a DTSTAMP. The UID must be globally unique and, more importantly, stable: it is the identity of the event forever. Re-import a file with the same UID and the calendar updates the existing entry; change the UID and you get a duplicate. DTSTAMP records when this iCalendar object was created and is always in UTC, ending with a Z.
DTSTART says when the event begins, and its companion is either DTEND or DURATION — never both. For an event written with whole dates rather than times, DTEND is exclusive: a one-day event on 5 October has DTSTART;VALUE=DATE:20261005 and DTEND;VALUE=DATE:20261006. Getting that wrong by a day is the most frequent off-by-one bug in calendar code.
Everything else is optional but expected: SUMMARY is the title shown in the grid, DESCRIPTION the body text, LOCATION a free-form place. STATUS takes CONFIRMED, TENTATIVE or CANCELLED. TRANSP decides whether the event consumes your free/busy time — OPAQUE means busy, TRANSPARENT means free. SEQUENCE is a revision counter that starts at 0 and increases every time you send a corrected version of the same UID.
Folding and escaping: why lines break mid-word
No content line may exceed 75 octets. Longer lines are folded: the writer inserts CRLF followed by a single space, and the reader removes exactly that sequence to rebuild the original. The break can land anywhere, including inside a word, which is why a long description in a raw .ics file looks mangled. The count is in octets, not characters — Cyrillic letters take two bytes in UTF-8 and emoji take four, so a Russian description folds roughly twice as often as an English one of the same length.
Inside a TEXT value, four characters carry special meaning and must be escaped: a backslash becomes \\, a semicolon \;, a comma \, and a line break \n. A comma that is not escaped in a DESCRIPTION is read as a value separator and can silently truncate your text. URI values such as URL, and date-time values such as DTSTART, are not escaped at all — the rules differ per value type.
The practical consequence is simple: do not hand-edit a folded file casually. Deleting the leading space of a continuation line changes it into a new, meaningless property, and most parsers will reject the whole component rather than guess.
Alarms, categories and the extras
A reminder is a VALARM component nested inside the VEVENT. It needs an ACTION — DISPLAY for an on-screen notice, AUDIO for a sound, EMAIL for a message — and a TRIGGER. A relative trigger is a duration counted from the start: TRIGGER:-PT15M is fifteen minutes before, TRIGGER:-P1D is one day before, TRIGGER:PT0S is exactly at the start. DISPLAY alarms also require a DESCRIPTION, which is the text of the notification.
CATEGORIES holds a comma-separated list of labels. RFC 7986, published in 2016, added properties that modern clients understand: COLOR takes a CSS3 colour name such as tomato or lightseagreen, IMAGE attaches a picture, and CONFERENCE carries a video-call URL with a FEATURE parameter. ORGANIZER and ATTENDEE both hold a mailto: URI and take parameters such as CN for the display name, ROLE, PARTSTAT for the response status and RSVP to request one.
What apps actually do with the file
There are two ways a calendar consumes an .ics: import and subscription. Importing copies the events in once and forgets where they came from — later changes to the file are invisible. Subscribing to a URL (often written webcal://) makes the client re-fetch periodically, so the publisher stays in control but subscribers usually cannot edit anything. A file you email to somebody is always an import.
Clients drop what they do not support, quietly. Custom X- properties disappear, COLOR is ignored by several popular apps, EMAIL alarms are frequently stripped, and a few mobile clients refuse attachments altogether. A file being valid is not a promise that it will look identical everywhere — it is only a promise that nothing will be misread.
When an import goes wrong, check five lines before anything else: BEGIN/END pairs that match, UID, DTSTAMP, DTSTART and the DTEND that goes with it. In practice those account for most rejected files.
The takeaway
An .ics file is short enough to read end to end, and almost every import failure is visible in the first few lines. Match your BEGIN and END pairs, keep the UID stable, write DTSTAMP in UTC, remember that an all-day DTEND is exclusive, and let a generator handle the 75-octet folding and the escaping for you.
Build an event and download the .ics file
More guides
Sep2026Recurring events and RRULE: every-second-Tuesday without losing your mind
One line of a calendar file can describe a thousand meetings. Here is how FREQ, INTERVAL, BYDAY and BYSETPOS fit together, when to reach for COUNT instead of UNTIL, and what daylight saving does to a weekly stand-up.
Jun2026Time zones in calendar invites: UTC, floating times and VTIMEZONE
A calendar file can say nine o'clock in three different ways, and they do not mean the same thing. Here is what TZID, the trailing Z and floating times actually promise — and what a VTIMEZONE block is doing in your file.