diff --git a/frontend/src/Helpers/dragTypes.js b/frontend/src/Helpers/dragTypes.js
index ed6ba080d..b4d02ffb0 100644
--- a/frontend/src/Helpers/dragTypes.js
+++ b/frontend/src/Helpers/dragTypes.js
@@ -1,3 +1,4 @@
 export const QUALITY_PROFILE_ITEM = 'qualityProfileItem';
+export const QUALITY_PROFILE_FORMAT_ITEM = 'qualityProfileFormatItem';
 export const DELAY_PROFILE = 'delayProfile';
 export const TABLE_COLUMN = 'tableColumn';
diff --git a/frontend/src/Settings/CustomFormats/CustomFormats/CustomFormat.js b/frontend/src/Settings/CustomFormats/CustomFormats/CustomFormat.js
index d389ff536..510f5b555 100644
--- a/frontend/src/Settings/CustomFormats/CustomFormats/CustomFormat.js
+++ b/frontend/src/Settings/CustomFormats/CustomFormats/CustomFormat.js
@@ -1,11 +1,12 @@
 import PropTypes from 'prop-types';
 import React, { Component } from 'react';
+import split from 'Utilities/String/split';
 import { icons, kinds } from 'Helpers/Props';
 import Card from 'Components/Card';
 import Label from 'Components/Label';
 import IconButton from 'Components/Link/IconButton';
 import ConfirmModal from 'Components/Modal/ConfirmModal';
-// import EditCustomFormatModalConnector from './EditCustomFormatModalConnector';
+import EditCustomFormatModalConnector from './EditCustomFormatModalConnector';
 import styles from './CustomFormat.css';
 
 class CustomFormat extends Component {
@@ -62,15 +63,15 @@ class CustomFormat extends Component {
 
   render() {
     const {
-      // id,
+      id,
       name,
-      items,
+      formatTags,
       isDeleting
     } = this.props;
 
     return (
       <Card
-        className={styles.CustomFormat}
+        className={styles.customFormat}
         overlayContent={true}
         onPress={this.onEditCustomFormatPress}
       >
@@ -87,32 +88,31 @@ class CustomFormat extends Component {
           />
         </div>
 
-        <div className={styles.formats}>
+        <div>
           {
-            items.map((item) => {
-              if (!item.allowed) {
+            split(formatTags).map((item) => {
+              if (!item) {
                 return null;
               }
 
               return (
                 <Label
-                  key={item.quality.id}
-                  kind={kinds.default}
-                  title={null}
+                  key={item}
+                  kind={kinds.DEFAULT}
                 >
-                  {item.quality.name}
+                  {item}
                 </Label>
               );
             })
           }
         </div>
 
-        {/* <EditCustomFormatModalConnector
+        <EditCustomFormatModalConnector
           id={id}
           isOpen={this.state.isEditCustomFormatModalOpen}
           onModalClose={this.onEditCustomFormatModalClose}
           onDeleteCustomFormatPress={this.onDeleteCustomFormatPress}
-        /> */}
+        />
 
         <ConfirmModal
           isOpen={this.state.isDeleteCustomFormatModalOpen}
@@ -132,7 +132,7 @@ class CustomFormat extends Component {
 CustomFormat.propTypes = {
   id: PropTypes.number.isRequired,
   name: PropTypes.string.isRequired,
-  items: PropTypes.arrayOf(PropTypes.object).isRequired,
+  formatTags: PropTypes.string.isRequired,
   isDeleting: PropTypes.bool.isRequired,
   onConfirmDeleteCustomFormat: PropTypes.func.isRequired,
   onCloneCustomFormatPress: PropTypes.func.isRequired
diff --git a/frontend/src/Settings/CustomFormats/CustomFormats/CustomFormats.js b/frontend/src/Settings/CustomFormats/CustomFormats/CustomFormats.js
index f17ad18d4..9bc6f90d5 100644
--- a/frontend/src/Settings/CustomFormats/CustomFormats/CustomFormats.js
+++ b/frontend/src/Settings/CustomFormats/CustomFormats/CustomFormats.js
@@ -7,7 +7,7 @@ import Card from 'Components/Card';
 import Icon from 'Components/Icon';
 import PageSectionContent from 'Components/Page/PageSectionContent';
 import CustomFormat from './CustomFormat';
-// import EditCustomFormatModalConnector from './EditCustomFormatModalConnector';
+import EditCustomFormatModalConnector from './EditCustomFormatModalConnector';
 import styles from './CustomFormats.css';
 
 class CustomFormats extends Component {
@@ -57,7 +57,7 @@ class CustomFormats extends Component {
           errorMessage="Unable to load Custom Formats"
           {...otherProps}c={true}
         >
-          <div className={styles.CustomFormats}>
+          <div className={styles.customFormats}>
             {
               items.sort(sortByName).map((item) => {
                 return (
@@ -85,11 +85,10 @@ class CustomFormats extends Component {
             </Card>
           </div>
 
-          {/*
           <EditCustomFormatModalConnector
             isOpen={this.state.isCustomFormatModalOpen}
             onModalClose={this.onModalClose}
-          /> */}
+          />
 
         </PageSectionContent>
       </FieldSet>
diff --git a/frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModal.js b/frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModal.js
new file mode 100644
index 000000000..3011f928c
--- /dev/null
+++ b/frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModal.js
@@ -0,0 +1,61 @@
+import PropTypes from 'prop-types';
+import React, { Component } from 'react';
+import { sizes } from 'Helpers/Props';
+import Modal from 'Components/Modal/Modal';
+import EditCustomFormatModalContentConnector from './EditCustomFormatModalContentConnector';
+
+class EditCustomFormatModal extends Component {
+
+  //
+  // Lifecycle
+
+  constructor(props, context) {
+    super(props, context);
+
+    this.state = {
+      height: 'auto'
+    };
+  }
+
+  //
+  // Listeners
+
+  onContentHeightChange = (height) => {
+    if (this.state.height === 'auto' || height > this.state.height) {
+      this.setState({ height });
+    }
+  }
+
+  //
+  // Render
+
+  render() {
+    const {
+      isOpen,
+      onModalClose,
+      ...otherProps
+    } = this.props;
+
+    return (
+      <Modal
+        style={{ height: `${this.state.height}px` }}
+        isOpen={isOpen}
+        size={sizes.EXTRA_LARGE}
+        onModalClose={onModalClose}
+      >
+        <EditCustomFormatModalContentConnector
+          {...otherProps}
+          onContentHeightChange={this.onContentHeightChange}
+          onModalClose={onModalClose}
+        />
+      </Modal>
+    );
+  }
+}
+
+EditCustomFormatModal.propTypes = {
+  isOpen: PropTypes.bool.isRequired,
+  onModalClose: PropTypes.func.isRequired
+};
+
+export default EditCustomFormatModal;
diff --git a/frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalConnector.js b/frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalConnector.js
new file mode 100644
index 000000000..d500cfd9f
--- /dev/null
+++ b/frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalConnector.js
@@ -0,0 +1,43 @@
+import PropTypes from 'prop-types';
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import { clearPendingChanges } from 'Store/Actions/baseActions';
+import EditCustomFormatModal from './EditCustomFormatModal';
+
+function mapStateToProps() {
+  return {};
+}
+
+const mapDispatchToProps = {
+  clearPendingChanges
+};
+
+class EditCustomFormatModalConnector extends Component {
+
+  //
+  // Listeners
+
+  onModalClose = () => {
+    this.props.clearPendingChanges({ section: 'settings.customFormats' });
+    this.props.onModalClose();
+  }
+
+  //
+  // Render
+
+  render() {
+    return (
+      <EditCustomFormatModal
+        {...this.props}
+        onModalClose={this.onModalClose}
+      />
+    );
+  }
+}
+
+EditCustomFormatModalConnector.propTypes = {
+  onModalClose: PropTypes.func.isRequired,
+  clearPendingChanges: PropTypes.func.isRequired
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(EditCustomFormatModalConnector);
diff --git a/frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalContent.css b/frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalContent.css
new file mode 100644
index 000000000..2f6589933
--- /dev/null
+++ b/frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalContent.css
@@ -0,0 +1,18 @@
+.formGroupsContainer {
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.formGroupWrapper {
+  flex: 0 0 calc($formGroupSmallWidth - 100px);
+}
+
+.deleteButtonContainer {
+  margin-right: auto;
+}
+
+@media only screen and (max-width: $breakpointLarge) {
+  .formGroupsContainer {
+    display: block;
+  }
+}
diff --git a/frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalContent.js b/frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalContent.js
new file mode 100644
index 000000000..ca1389665
--- /dev/null
+++ b/frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalContent.js
@@ -0,0 +1,131 @@
+import PropTypes from 'prop-types';
+import React, { Component } from 'react';
+import { inputTypes, sizes } from 'Helpers/Props';
+import Button from 'Components/Link/Button';
+import SpinnerErrorButton from 'Components/Link/SpinnerErrorButton';
+import LoadingIndicator from 'Components/Loading/LoadingIndicator';
+import ModalContent from 'Components/Modal/ModalContent';
+import ModalHeader from 'Components/Modal/ModalHeader';
+import ModalBody from 'Components/Modal/ModalBody';
+import ModalFooter from 'Components/Modal/ModalFooter';
+import Form from 'Components/Form/Form';
+import FormGroup from 'Components/Form/FormGroup';
+import FormLabel from 'Components/Form/FormLabel';
+import FormInputGroup from 'Components/Form/FormInputGroup';
+import styles from './EditCustomFormatModalContent.css';
+
+class EditCustomFormatModalContent extends Component {
+
+  //
+  // Render
+
+  render() {
+    const {
+      isFetching,
+      error,
+      isSaving,
+      saveError,
+      item,
+      onInputChange,
+      onSavePress,
+      onModalClose,
+      ...otherProps
+    } = this.props;
+
+    const {
+      id,
+      name,
+      formatTags
+    } = item;
+
+    return (
+      <ModalContent onModalClose={onModalClose}>
+
+        <ModalHeader>
+          {id ? 'Edit Custom Format' : 'Add Custom Format'}
+        </ModalHeader>
+
+        <ModalBody>
+          <div>
+            {
+              isFetching &&
+                <LoadingIndicator />
+            }
+
+            {
+              !isFetching && !!error &&
+                <div>Unable to add a new custom format, please try again.</div>
+            }
+
+            {
+              !isFetching && !error &&
+                <Form
+                  {...otherProps}
+                >
+                  <div className={styles.formGroupsContainer}>
+                    <div className={styles.formGroupWrapper}>
+                      <FormGroup size={sizes.EXTRA_SMALL}>
+                        <FormLabel size={sizes.SMALL}>
+                          Name
+                        </FormLabel>
+
+                        <FormInputGroup
+                          type={inputTypes.TEXT}
+                          name="name"
+                          {...name}
+                          onChange={onInputChange}
+                        />
+                      </FormGroup>
+
+                      <FormGroup size={sizes.EXTRA_SMALL}>
+                        <FormLabel size={sizes.SMALL}>
+                          Format Tags
+                        </FormLabel>
+
+                        <FormInputGroup
+                          type={inputTypes.TEXT_TAG}
+                          name="formatTags"
+                          {...formatTags}
+                          onChange={onInputChange}
+                        />
+                      </FormGroup>
+                    </div>
+                  </div>
+                </Form>
+
+            }
+          </div>
+        </ModalBody>
+        <ModalFooter>
+          <Button
+            onPress={onModalClose}
+          >
+            Cancel
+          </Button>
+
+          <SpinnerErrorButton
+            isSpinning={isSaving}
+            error={saveError}
+            onPress={onSavePress}
+          >
+            Save
+          </SpinnerErrorButton>
+        </ModalFooter>
+      </ModalContent>
+    );
+  }
+}
+
+EditCustomFormatModalContent.propTypes = {
+  isFetching: PropTypes.bool.isRequired,
+  error: PropTypes.object,
+  isSaving: PropTypes.bool.isRequired,
+  saveError: PropTypes.object,
+  item: PropTypes.object.isRequired,
+  onInputChange: PropTypes.func.isRequired,
+  onSavePress: PropTypes.func.isRequired,
+  onContentHeightChange: PropTypes.func.isRequired,
+  onModalClose: PropTypes.func.isRequired
+};
+
+export default EditCustomFormatModalContent;
diff --git a/frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalContentConnector.js b/frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalContentConnector.js
new file mode 100644
index 000000000..c73fcf174
--- /dev/null
+++ b/frontend/src/Settings/CustomFormats/CustomFormats/EditCustomFormatModalContentConnector.js
@@ -0,0 +1,74 @@
+import PropTypes from 'prop-types';
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import { createSelector } from 'reselect';
+import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
+import { setCustomFormatValue, saveCustomFormat } from 'Store/Actions/settingsActions';
+import EditCustomFormatModalContent from './EditCustomFormatModalContent';
+
+function createMapStateToProps() {
+  return createSelector(
+    (state) => state.settings.advancedSettings,
+    createProviderSettingsSelector('customFormats'),
+    (advancedSettings, customFormat) => {
+      return {
+        advancedSettings,
+        ...customFormat
+      };
+    }
+  );
+}
+
+const mapDispatchToProps = {
+  setCustomFormatValue,
+  saveCustomFormat
+};
+
+class EditCustomFormatModalContentConnector extends Component {
+
+  //
+  // Lifecycle
+
+  componentDidUpdate(prevProps, prevState) {
+    if (prevProps.isSaving && !this.props.isSaving && !this.props.saveError) {
+      this.props.onModalClose();
+    }
+  }
+
+  //
+  // Listeners
+
+  onInputChange = ({ name, value }) => {
+    this.props.setCustomFormatValue({ name, value });
+  }
+
+  onSavePress = () => {
+    this.props.saveCustomFormat({ id: this.props.id });
+  }
+
+  //
+  // Render
+
+  render() {
+    return (
+      <EditCustomFormatModalContent
+        {...this.props}
+        onSavePress={this.onSavePress}
+        onInputChange={this.onInputChange}
+      />
+    );
+  }
+}
+
+EditCustomFormatModalContentConnector.propTypes = {
+  id: PropTypes.number,
+  isFetching: PropTypes.bool.isRequired,
+  isSaving: PropTypes.bool.isRequired,
+  saveError: PropTypes.object,
+  item: PropTypes.object.isRequired,
+  setCustomFormatValue: PropTypes.func.isRequired,
+  saveCustomFormat: PropTypes.func.isRequired,
+  onModalClose: PropTypes.func.isRequired
+};
+
+export default connect(createMapStateToProps, mapDispatchToProps)(EditCustomFormatModalContentConnector);
diff --git a/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContent.js b/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContent.js
index 6f6a85ae7..e72ff3665 100644
--- a/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContent.js
+++ b/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContent.js
@@ -15,6 +15,7 @@ import FormGroup from 'Components/Form/FormGroup';
 import FormLabel from 'Components/Form/FormLabel';
 import FormInputGroup from 'Components/Form/FormInputGroup';
 import QualityProfileItems from './QualityProfileItems';
+import QualityProfileFormatItems from './QualityProfileFormatItems';
 import styles from './EditQualityProfileModalContent.css';
 
 const MODAL_BODY_PADDING = parseInt(dimensions.modalBodyPadding);
@@ -92,6 +93,7 @@ class EditQualityProfileModalContent extends Component {
       isSaving,
       saveError,
       qualities,
+      customFormats,
       languages,
       item,
       isInUse,
@@ -109,11 +111,13 @@ class EditQualityProfileModalContent extends Component {
       name,
       upgradeAllowed,
       cutoff,
+      formatCutoff,
       language,
-      items
+      items,
+      formatItems
     } = item;
 
-    const languageId = language.value.id;
+    const languageId = language ? language.value.id : 0;
 
     return (
       <ModalContent onModalClose={onModalClose}>
@@ -181,7 +185,7 @@ class EditQualityProfileModalContent extends Component {
                           upgradeAllowed.value &&
                             <FormGroup size={sizes.EXTRA_SMALL}>
                               <FormLabel size={sizes.SMALL}>
-                              Upgrade Until
+                              Upgrade Until Quality
                               </FormLabel>
 
                               <FormInputGroup
@@ -195,6 +199,24 @@ class EditQualityProfileModalContent extends Component {
                             </FormGroup>
                         }
 
+                        {
+                          upgradeAllowed.value &&
+                            <FormGroup size={sizes.EXTRA_SMALL}>
+                              <FormLabel size={sizes.SMALL}>
+                              Upgrade Until Format
+                              </FormLabel>
+
+                              <FormInputGroup
+                                type={inputTypes.SELECT}
+                                name="formatCutoff"
+                                {...formatCutoff}
+                                values={customFormats}
+                                helpText="Once this custom format is reached Radarr will no longer download movies"
+                                onChange={onCutoffChange}
+                              />
+                            </FormGroup>
+                        }
+
                         <FormGroup size={sizes.EXTRA_SMALL}>
                           <FormLabel size={sizes.SMALL}>
                           Language
@@ -220,6 +242,15 @@ class EditQualityProfileModalContent extends Component {
                           {...otherProps}
                         />
                       </div>
+
+                      <div className={styles.formGroupWrapper}>
+                        <QualityProfileFormatItems
+                          profileFormatItems={formatItems.value}
+                          errors={formatItems.errors}
+                          warnings={formatItems.warnings}
+                          {...otherProps}
+                        />
+                      </div>
                     </div>
                   </Form>
 
@@ -282,6 +313,7 @@ EditQualityProfileModalContent.propTypes = {
   isSaving: PropTypes.bool.isRequired,
   saveError: PropTypes.object,
   qualities: PropTypes.arrayOf(PropTypes.object).isRequired,
+  customFormats: PropTypes.arrayOf(PropTypes.object).isRequired,
   languages: PropTypes.arrayOf(PropTypes.object).isRequired,
   item: PropTypes.object.isRequired,
   isInUse: PropTypes.bool.isRequired,
diff --git a/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContentConnector.js b/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContentConnector.js
index b73f74d80..a1609338c 100644
--- a/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContentConnector.js
+++ b/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContentConnector.js
@@ -61,6 +61,36 @@ function createQualitiesSelector() {
   );
 }
 
+function createFormatsSelector() {
+  return createSelector(
+    createProviderSettingsSelector('qualityProfiles'),
+    (customFormat) => {
+      const items = customFormat.item.formatItems;
+      if (!items || !items.value) {
+        return [];
+      }
+
+      return _.reduceRight(items.value, (result, { allowed, id, name, format }) => {
+        if (allowed) {
+          if (id) {
+            result.push({
+              key: id,
+              value: name
+            });
+          } else {
+            result.push({
+              key: format.id,
+              value: format.name
+            });
+          }
+        }
+
+        return result;
+      }, []);
+    }
+  );
+}
+
 function createLanguagesSelector() {
   return createSelector(
     (state) => state.settings.languages,
@@ -87,11 +117,13 @@ function createMapStateToProps() {
   return createSelector(
     createProviderSettingsSelector('qualityProfiles'),
     createQualitiesSelector(),
+    createFormatsSelector(),
     createLanguagesSelector(),
     createProfileInUseSelector('qualityProfileId'),
-    (qualityProfile, qualities, languages, isInUse) => {
+    (qualityProfile, qualities, customFormats, languages, isInUse) => {
       return {
         qualities,
+        customFormats,
         languages,
         ...qualityProfile,
         isInUse
@@ -161,6 +193,30 @@ class EditQualityProfileModalContentConnector extends Component {
     }
   }
 
+  ensureFormatCutoff = (qualityProfile) => {
+    const cutoff = qualityProfile.formatCutoff.value;
+
+    const cutoffItem = _.find(qualityProfile.formatItems.value, (i) => {
+      if (!cutoff) {
+        return false;
+      }
+
+      return i.id === cutoff || (i.format && i.format.id === cutoff);
+    });
+
+    // If the cutoff isn't allowed anymore or there isn't a cutoff set one
+    if (!cutoff || !cutoffItem || !cutoffItem.allowed) {
+      const firstAllowed = _.find(qualityProfile.formatItems.value, { allowed: true });
+      let cutoffId = null;
+
+      if (firstAllowed) {
+        cutoffId = firstAllowed.format ? firstAllowed.format.id : firstAllowed.id;
+      }
+
+      this.props.setQualityProfileValue({ name: 'formatCutoff', value: cutoffId });
+    }
+  }
+
   //
   // Listeners
 
@@ -211,6 +267,21 @@ class EditQualityProfileModalContentConnector extends Component {
     this.ensureCutoff(qualityProfile);
   }
 
+  onQualityProfileFormatItemAllowedChange = (id, allowed) => {
+    const qualityProfile = _.cloneDeep(this.props.item);
+    const formatItems = qualityProfile.formatItems.value;
+    const item = _.find(qualityProfile.formatItems.value, (i) => i.format && i.format.id === id);
+
+    item.allowed = allowed;
+
+    this.props.setQualityProfileValue({
+      name: 'formatItems',
+      value: formatItems
+    });
+
+    this.ensureFormatCutoff(qualityProfile);
+  }
+
   onItemGroupAllowedChange = (id, allowed) => {
     const qualityProfile = _.cloneDeep(this.props.item);
     const items = qualityProfile.items.value;
@@ -427,6 +498,39 @@ class EditQualityProfileModalContentConnector extends Component {
     });
   }
 
+  onQualityProfileFormatItemDragMove = (dragIndex, dropIndex) => {
+    if (this.state.dragIndex !== dragIndex || this.state.dropIndex !== dropIndex) {
+      this.setState({
+        dragIndex,
+        dropIndex
+      });
+    }
+  }
+
+  onQualityProfileFormatItemDragEnd = ({ id }, didDrop) => {
+    const {
+      dragIndex,
+      dropIndex
+    } = this.state;
+
+    if (didDrop && dropIndex !== null) {
+      const qualityProfile = _.cloneDeep(this.props.item);
+
+      const formats = qualityProfile.formatItems.value.splice(dragIndex, 1);
+      qualityProfile.formatItems.value.splice(dropIndex, 0, formats[0]);
+
+      this.props.setQualityProfileValue({
+        name: 'formatItems',
+        value: qualityProfile.formatItems.value
+      });
+    }
+
+    this.setState({
+      dragIndex: null,
+      dropIndex: null
+    });
+  }
+
   onToggleEditGroupsMode = () => {
     this.setState({ editGroups: !this.state.editGroups });
   }
@@ -450,10 +554,13 @@ class EditQualityProfileModalContentConnector extends Component {
         onCreateGroupPress={this.onCreateGroupPress}
         onDeleteGroupPress={this.onDeleteGroupPress}
         onQualityProfileItemAllowedChange={this.onQualityProfileItemAllowedChange}
+        onQualityProfileFormatItemAllowedChange={this.onQualityProfileFormatItemAllowedChange}
         onItemGroupAllowedChange={this.onItemGroupAllowedChange}
         onItemGroupNameChange={this.onItemGroupNameChange}
         onQualityProfileItemDragMove={this.onQualityProfileItemDragMove}
         onQualityProfileItemDragEnd={this.onQualityProfileItemDragEnd}
+        onQualityProfileFormatItemDragMove={this.onQualityProfileFormatItemDragMove}
+        onQualityProfileFormatItemDragEnd={this.onQualityProfileFormatItemDragEnd}
         onToggleEditGroupsMode={this.onToggleEditGroupsMode}
       />
     );
diff --git a/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItem.css b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItem.css
new file mode 100644
index 000000000..1c139079b
--- /dev/null
+++ b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItem.css
@@ -0,0 +1,44 @@
+.qualityProfileFormatItem {
+  display: flex;
+  align-items: stretch;
+  width: 100%;
+  border: 1px solid #aaa;
+  border-radius: 4px;
+  background: #fafafa;
+}
+
+.checkContainer {
+  position: relative;
+  margin-right: 4px;
+  margin-bottom: 7px;
+  margin-left: 8px;
+}
+
+.formatName {
+  display: flex;
+  flex-grow: 1;
+  margin-bottom: 0;
+  margin-left: 2px;
+  font-weight: normal;
+  line-height: 36px;
+  cursor: pointer;
+}
+
+.dragHandle {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+  margin-left: auto;
+  width: $dragHandleWidth;
+  text-align: center;
+  cursor: grab;
+}
+
+.dragIcon {
+  top: 0;
+}
+
+.isDragging {
+  opacity: 0.25;
+}
diff --git a/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItem.js b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItem.js
new file mode 100644
index 000000000..ec1b75b8f
--- /dev/null
+++ b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItem.js
@@ -0,0 +1,83 @@
+import PropTypes from 'prop-types';
+import React, { Component } from 'react';
+import classNames from 'classnames';
+import { icons } from 'Helpers/Props';
+import Icon from 'Components/Icon';
+import CheckInput from 'Components/Form/CheckInput';
+import styles from './QualityProfileFormatItem.css';
+
+class QualityProfileFormatItem extends Component {
+
+  //
+  // Listeners
+
+  onAllowedChange = ({ value }) => {
+    const {
+      formatId,
+      onQualityProfileFormatItemAllowedChange
+    } = this.props;
+
+    onQualityProfileFormatItemAllowedChange(formatId, value);
+  }
+
+  //
+  // Render
+
+  render() {
+    const {
+      name,
+      allowed,
+      isDragging,
+      connectDragSource
+    } = this.props;
+
+    return (
+      <div
+        className={classNames(
+          styles.qualityProfileFormatItem,
+          isDragging && styles.isDragging
+        )}
+      >
+        <label
+          className={styles.formatName}
+        >
+          <CheckInput
+            containerClassName={styles.checkContainer}
+            name={name}
+            value={allowed}
+            onChange={this.onAllowedChange}
+          />
+          {name}
+        </label>
+
+        {
+          connectDragSource(
+            <div className={styles.dragHandle}>
+              <Icon
+                className={styles.dragIcon}
+                name={icons.REORDER}
+              />
+            </div>
+          )
+        }
+      </div>
+    );
+  }
+}
+
+QualityProfileFormatItem.propTypes = {
+  formatId: PropTypes.number.isRequired,
+  name: PropTypes.string.isRequired,
+  allowed: PropTypes.bool.isRequired,
+  sortIndex: PropTypes.number.isRequired,
+  isDragging: PropTypes.bool.isRequired,
+  connectDragSource: PropTypes.func,
+  onQualityProfileFormatItemAllowedChange: PropTypes.func
+};
+
+QualityProfileFormatItem.defaultProps = {
+  // The drag preview will not connect the drag handle.
+  connectDragSource: (node) => node
+};
+
+export default QualityProfileFormatItem;
diff --git a/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItemDragPreview.css b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItemDragPreview.css
new file mode 100644
index 000000000..b927d9bce
--- /dev/null
+++ b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItemDragPreview.css
@@ -0,0 +1,4 @@
+.dragPreview {
+  width: 380px;
+  opacity: 0.75;
+}
diff --git a/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItemDragPreview.js b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItemDragPreview.js
new file mode 100644
index 000000000..8b459fd4b
--- /dev/null
+++ b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItemDragPreview.js
@@ -0,0 +1,88 @@
+import PropTypes from 'prop-types';
+import React, { Component } from 'react';
+import { DragLayer } from 'react-dnd';
+import dimensions from 'Styles/Variables/dimensions.js';
+import { QUALITY_PROFILE_FORMAT_ITEM } from 'Helpers/dragTypes';
+import DragPreviewLayer from 'Components/DragPreviewLayer';
+import QualityProfileFormatItem from './QualityProfileFormatItem';
+import styles from './QualityProfileFormatItemDragPreview.css';
+
+const formGroupSmallWidth = parseInt(dimensions.formGroupSmallWidth);
+const formLabelLargeWidth = parseInt(dimensions.formLabelLargeWidth);
+const formLabelRightMarginWidth = parseInt(dimensions.formLabelRightMarginWidth);
+const dragHandleWidth = parseInt(dimensions.dragHandleWidth);
+
+function collectDragLayer(monitor) {
+  return {
+    item: monitor.getItem(),
+    itemType: monitor.getItemType(),
+    currentOffset: monitor.getSourceClientOffset()
+  };
+}
+
+class QualityProfileFormatItemDragPreview extends Component {
+
+  //
+  // Render
+
+  render() {
+    const {
+      item,
+      itemType,
+      currentOffset
+    } = this.props;
+
+    if (!currentOffset || itemType !== QUALITY_PROFILE_FORMAT_ITEM) {
+      return null;
+    }
+
+    // The offset is shifted because the drag handle is on the right edge of the
+    // list item and the preview is wider than the drag handle.
+
+    const { x, y } = currentOffset;
+    const handleOffset = formGroupSmallWidth - formLabelLargeWidth - formLabelRightMarginWidth - dragHandleWidth;
+    const transform = `translate3d(${x - handleOffset}px, ${y}px, 0)`;
+
+    const style = {
+      position: 'absolute',
+      WebkitTransform: transform,
+      msTransform: transform,
+      transform
+    };
+
+    const {
+      formatId,
+      name,
+      allowed,
+      sortIndex
+    } = item;
+
+    return (
+      <DragPreviewLayer>
+        <div
+          className={styles.dragPreview}
+          style={style}
+        >
+          <QualityProfileFormatItem
+            formatId={formatId}
+            name={name}
+            allowed={allowed}
+            sortIndex={sortIndex}
+            isDragging={false}
+          />
+        </div>
+      </DragPreviewLayer>
+    );
+  }
+}
+
+QualityProfileFormatItemDragPreview.propTypes = {
+  item: PropTypes.object,
+  itemType: PropTypes.string,
+  currentOffset: PropTypes.shape({
+    x: PropTypes.number.isRequired,
+    y: PropTypes.number.isRequired
+  })
+};
+
+export default DragLayer(collectDragLayer)(QualityProfileFormatItemDragPreview);
diff --git a/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItemDragSource.css b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItemDragSource.css
new file mode 100644
index 000000000..c5dd1ebc3
--- /dev/null
+++ b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItemDragSource.css
@@ -0,0 +1,18 @@
+.qualityProfileFormatItemDragSource {
+  padding: 4px 0;
+}
+
+.qualityProfileFormatItemPlaceholder {
+  width: 100%;
+  height: 36px;
+  border: 1px dotted #aaa;
+  border-radius: 4px;
+}
+
+.qualityProfileFormatItemPlaceholderBefore {
+  margin-bottom: 8px;
+}
+
+.qualityProfileFormatItemPlaceholderAfter {
+  margin-top: 8px;
+}
diff --git a/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItemDragSource.js b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItemDragSource.js
new file mode 100644
index 000000000..4a07cb684
--- /dev/null
+++ b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItemDragSource.js
@@ -0,0 +1,157 @@
+import PropTypes from 'prop-types';
+import React, { Component } from 'react';
+import { findDOMNode } from 'react-dom';
+import { DragSource, DropTarget } from 'react-dnd';
+import classNames from 'classnames';
+import { QUALITY_PROFILE_FORMAT_ITEM } from 'Helpers/dragTypes';
+import QualityProfileFormatItem from './QualityProfileFormatItem';
+import styles from './QualityProfileFormatItemDragSource.css';
+
+const qualityProfileFormatItemDragSource = {
+  beginDrag({ formatId, name, allowed, sortIndex }) {
+    return {
+      formatId,
+      name,
+      allowed,
+      sortIndex
+    };
+  },
+
+  endDrag(props, monitor, component) {
+    props.onQualityProfileFormatItemDragEnd(monitor.getItem(), monitor.didDrop());
+  }
+};
+
+const qualityProfileFormatItemDropTarget = {
+  hover(props, monitor, component) {
+    const dragIndex = monitor.getItem().sortIndex;
+    const hoverIndex = props.sortIndex;
+
+    const hoverBoundingRect = findDOMNode(component).getBoundingClientRect();
+    const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
+    const clientOffset = monitor.getClientOffset();
+    const hoverClientY = clientOffset.y - hoverBoundingRect.top;
+
+    // Moving up, only trigger if drag position is above 50%
+    if (dragIndex < hoverIndex && hoverClientY > hoverMiddleY) {
+      return;
+    }
+
+    // Moving down, only trigger if drag position is below 50%
+    if (dragIndex > hoverIndex && hoverClientY < hoverMiddleY) {
+      return;
+    }
+
+    props.onQualityProfileFormatItemDragMove(dragIndex, hoverIndex);
+  }
+};
+
+function collectDragSource(connect, monitor) {
+  return {
+    connectDragSource: connect.dragSource(),
+    isDragging: monitor.isDragging()
+  };
+}
+
+function collectDropTarget(connect, monitor) {
+  return {
+    connectDropTarget: connect.dropTarget(),
+    isOver: monitor.isOver()
+  };
+}
+
+class QualityProfileFormatItemDragSource extends Component {
+
+  //
+  // Render
+
+  render() {
+    const {
+      formatId,
+      name,
+      allowed,
+      sortIndex,
+      isDragging,
+      isDraggingUp,
+      isDraggingDown,
+      isOver,
+      connectDragSource,
+      connectDropTarget,
+      onQualityProfileFormatItemAllowedChange
+    } = this.props;
+
+    const isBefore = !isDragging && isDraggingUp && isOver;
+    const isAfter = !isDragging && isDraggingDown && isOver;
+
+    // if (isDragging && !isOver) {
+    //   return null;
+    // }
+
+    return connectDropTarget(
+      <div
+        className={classNames(
+          styles.qualityProfileFormatItemDragSource,
+          isBefore && styles.isDraggingUp,
+          isAfter && styles.isDraggingDown
+        )}
+      >
+        {
+          isBefore &&
+            <div
+              className={classNames(
+                styles.qualityProfileFormatItemPlaceholder,
+                styles.qualityProfileFormatItemPlaceholderBefore
+              )}
+            />
+        }
+
+        <QualityProfileFormatItem
+          formatId={formatId}
+          name={name}
+          allowed={allowed}
+          sortIndex={sortIndex}
+          isDragging={isDragging}
+          isOver={isOver}
+          connectDragSource={connectDragSource}
+          onQualityProfileFormatItemAllowedChange={onQualityProfileFormatItemAllowedChange}
+        />
+
+        {
+          isAfter &&
+            <div
+              className={classNames(
+                styles.qualityProfileFormatItemPlaceholder,
+                styles.qualityProfileFormatItemPlaceholderAfter
+              )}
+            />
+        }
+      </div>
+    );
+  }
+}
+
+QualityProfileFormatItemDragSource.propTypes = {
+  formatId: PropTypes.number.isRequired,
+  name: PropTypes.string.isRequired,
+  allowed: PropTypes.bool.isRequired,
+  sortIndex: PropTypes.number.isRequired,
+  isDragging: PropTypes.bool,
+  isDraggingUp: PropTypes.bool,
+  isDraggingDown: PropTypes.bool,
+  isOver: PropTypes.bool,
+  connectDragSource: PropTypes.func,
+  connectDropTarget: PropTypes.func,
+  onQualityProfileFormatItemAllowedChange: PropTypes.func.isRequired,
+  onQualityProfileFormatItemDragMove: PropTypes.func.isRequired,
+  onQualityProfileFormatItemDragEnd: PropTypes.func.isRequired
+};
+
+export default DropTarget(
+  QUALITY_PROFILE_FORMAT_ITEM,
+  qualityProfileFormatItemDropTarget,
+  collectDropTarget
+)(DragSource(
+  QUALITY_PROFILE_FORMAT_ITEM,
+  qualityProfileFormatItemDragSource,
+  collectDragSource
+)(QualityProfileFormatItemDragSource));
diff --git a/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItems.css b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItems.css
new file mode 100644
index 000000000..42785b9f1
--- /dev/null
+++ b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItems.css
@@ -0,0 +1,6 @@
+.formats {
+  margin-top: 10px;
+  /* TODO: This should consider the number of languages in the list */
+  min-height: 550px;
+  user-select: none;
+}
diff --git a/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItems.js b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItems.js
new file mode 100644
index 000000000..e6e94abbe
--- /dev/null
+++ b/frontend/src/Settings/Profiles/Quality/QualityProfileFormatItems.js
@@ -0,0 +1,103 @@
+import PropTypes from 'prop-types';
+import React, { Component } from 'react';
+import FormGroup from 'Components/Form/FormGroup';
+import FormLabel from 'Components/Form/FormLabel';
+import FormInputHelpText from 'Components/Form/FormInputHelpText';
+import QualityProfileFormatItemDragSource from './QualityProfileFormatItemDragSource';
+import QualityProfileFormatItemDragPreview from './QualityProfileFormatItemDragPreview';
+import styles from './QualityProfileFormatItems.css';
+
+class QualityProfileFormatItems extends Component {
+
+  //
+  // Render
+
+  render() {
+    const {
+      dragIndex,
+      dropIndex,
+      profileFormatItems,
+      errors,
+      warnings,
+      ...otherProps
+    } = this.props;
+
+    const isDragging = dropIndex !== null;
+    const isDraggingUp = isDragging && dropIndex > dragIndex;
+    const isDraggingDown = isDragging && dropIndex < dragIndex;
+
+    return (
+      <FormGroup>
+        <FormLabel>Custom Formats</FormLabel>
+        <div>
+          <FormInputHelpText
+            text="Custom Formats higher in the list are more preferred. Only checked custom formats are wanted"
+          />
+
+          {
+            errors.map((error, index) => {
+              return (
+                <FormInputHelpText
+                  key={index}
+                  text={error.message}
+                  isError={true}
+                  isCheckInput={false}
+                />
+              );
+            })
+          }
+
+          {
+            warnings.map((warning, index) => {
+              return (
+                <FormInputHelpText
+                  key={index}
+                  text={warning.message}
+                  isWarning={true}
+                  isCheckInput={false}
+                />
+              );
+            })
+          }
+
+          <div className={styles.formats}>
+            {
+              profileFormatItems.map(({ allowed, format }, index) => {
+                return (
+                  <QualityProfileFormatItemDragSource
+                    key={format.id}
+                    formatId={format.id}
+                    name={format.name}
+                    allowed={allowed}
+                    sortIndex={index}
+                    isDragging={isDragging}
+                    isDraggingUp={isDraggingUp}
+                    isDraggingDown={isDraggingDown}
+                    {...otherProps}
+                  />
+                );
+              }).reverse()
+            }
+
+            <QualityProfileFormatItemDragPreview />
+          </div>
+        </div>
+      </FormGroup>
+    );
+  }
+}
+
+QualityProfileFormatItems.propTypes = {
+  dragIndex: PropTypes.number,
+  dropIndex: PropTypes.number,
+  profileFormatItems: PropTypes.arrayOf(PropTypes.object).isRequired,
+  errors: PropTypes.arrayOf(PropTypes.object),
+  warnings: PropTypes.arrayOf(PropTypes.object)
+};
+
+QualityProfileFormatItems.defaultProps = {
+  errors: [],
+  warnings: []
+};
+
+export default QualityProfileFormatItems;
diff --git a/package.json b/package.json
index fecd1b2aa..10a41739f 100644
--- a/package.json
+++ b/package.json
@@ -6,6 +6,7 @@
     "build": "gulp build",
     "start": "gulp watch",
     "watch": "gulp watch",
+    "clean": "git clean -fXd",
     "lint": "esprint check",
     "lint-fix": "eslint start --fix",
     "stylelint": "stylelint frontend/**/*.css --config frontend/.stylelintrc"
@@ -53,7 +54,7 @@
     "eslint": "6.0.1",
     "eslint-plugin-filenames": "1.3.2",
     "eslint-plugin-react": "7.14.2",
-    "esprint": "0.4.0",
+    "esprint": "0.5.0",
     "file-loader": "4.0.0",
     "filesize": "4.1.2",
     "fuse.js": "3.4.5",
diff --git a/src/NzbDrone.Api/Profiles/ProfileResource.cs b/src/NzbDrone.Api/Profiles/ProfileResource.cs
index 3ba652781..2f4df4f39 100644
--- a/src/NzbDrone.Api/Profiles/ProfileResource.cs
+++ b/src/NzbDrone.Api/Profiles/ProfileResource.cs
@@ -51,6 +51,17 @@ namespace NzbDrone.Api.Profiles
                 ? cutoffItem.Quality
                 : cutoffItem.Items.First().Quality;
 
+            var formatCutoffItem = model.FormatItems.First(q =>
+            {
+                if (q.Id == model.FormatCutoff) return true;
+
+                if (q.Format == null) return false;
+
+                return q.Format.Id == model.FormatCutoff;
+            });
+
+            var formatCutoff = formatCutoffItem.Format;
+
             return new ProfileResource
             {
                 Id = model.Id,
@@ -74,7 +85,7 @@ namespace NzbDrone.Api.Profiles
 
                     return new List<ProfileQualityItemResource> { ToResource(i) };
                 }).ToList(),
-                FormatCutoff = model.FormatCutoff.ToResource(),
+                FormatCutoff = formatCutoff.ToResource(),
                 FormatItems = model.FormatItems.ConvertAll(ToResource),
                 Language = model.Language
             };
@@ -112,7 +123,7 @@ namespace NzbDrone.Api.Profiles
                 Cutoff = resource.Cutoff.Id,
                 PreferredTags = resource.PreferredTags.Split(',').ToList(),
                 Items = resource.Items.ConvertAll(ToModel),
-                FormatCutoff = resource.FormatCutoff.ToModel(),
+                FormatCutoff = resource.FormatCutoff.ToModel().Id,
                 FormatItems = resource.FormatItems.ConvertAll(ToModel),
                 Language = resource.Language
             };
diff --git a/src/NzbDrone.Api/Profiles/ProfileSchemaModule.cs b/src/NzbDrone.Api/Profiles/ProfileSchemaModule.cs
index 433fe978d..595a3567f 100644
--- a/src/NzbDrone.Api/Profiles/ProfileSchemaModule.cs
+++ b/src/NzbDrone.Api/Profiles/ProfileSchemaModule.cs
@@ -45,7 +45,7 @@ namespace NzbDrone.Api.Profiles
             var profile = new Profile();
             profile.Cutoff = Quality.Unknown.Id;
             profile.Items = items;
-            profile.FormatCutoff = CustomFormat.None;
+            profile.FormatCutoff = CustomFormat.None.Id;
             profile.FormatItems = formatItems;
             profile.Language = Language.English;
 
diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/CutoffSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/CutoffSpecificationFixture.cs
index 3b3a15e70..2efd7de36 100644
--- a/src/NzbDrone.Core.Test/DecisionEngineTests/CutoffSpecificationFixture.cs
+++ b/src/NzbDrone.Core.Test/DecisionEngineTests/CutoffSpecificationFixture.cs
@@ -79,7 +79,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
                 {
                     Cutoff = Quality.HDTV720p.Id,
                     Items = Qualities.QualityFixture.GetDefaultQualities(),
-                    FormatCutoff = CustomFormats.CustomFormat.None,
+                    FormatCutoff = CustomFormats.CustomFormat.None.Id,
                     FormatItems = CustomFormatsFixture.GetSampleFormatItems("None", "My Format")
                 }, old, newQ).Should().BeFalse();
         }
diff --git a/src/NzbDrone.Core.Test/MovieTests/MovieRepositoryTests/MovieRepositoryFixture.cs b/src/NzbDrone.Core.Test/MovieTests/MovieRepositoryTests/MovieRepositoryFixture.cs
index c3e838bca..b93735053 100644
--- a/src/NzbDrone.Core.Test/MovieTests/MovieRepositoryTests/MovieRepositoryFixture.cs
+++ b/src/NzbDrone.Core.Test/MovieTests/MovieRepositoryTests/MovieRepositoryFixture.cs
@@ -24,7 +24,7 @@ namespace NzbDrone.Core.Test.MovieTests.MovieRepositoryTests
                 {
                     Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p),
                     FormatItems = CustomFormat.CustomFormatsFixture.GetDefaultFormatItems(),
-                    FormatCutoff = CustomFormats.CustomFormat.None,
+                    FormatCutoff = CustomFormats.CustomFormat.None.Id,
                     Cutoff = Quality.Bluray1080p.Id,
                     Name = "TestProfile"
                 };
diff --git a/src/NzbDrone.Core.Test/Profiles/ProfileRepositoryFixture.cs b/src/NzbDrone.Core.Test/Profiles/ProfileRepositoryFixture.cs
index d75b29f88..2f29fe20b 100644
--- a/src/NzbDrone.Core.Test/Profiles/ProfileRepositoryFixture.cs
+++ b/src/NzbDrone.Core.Test/Profiles/ProfileRepositoryFixture.cs
@@ -20,7 +20,7 @@ namespace NzbDrone.Core.Test.Profiles
             var profile = new Profile
                 {
                     Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p),
-                    FormatCutoff = CustomFormats.CustomFormat.None,
+                    FormatCutoff = CustomFormats.CustomFormat.None.Id,
                     FormatItems = CustomFormat.CustomFormatsFixture.GetDefaultFormatItems(),
                     Cutoff = Quality.Bluray1080p.Id,
                     Name = "TestProfile"
diff --git a/src/NzbDrone.Core.Test/Profiles/ProfileServiceFixture.cs b/src/NzbDrone.Core.Test/Profiles/ProfileServiceFixture.cs
index 4fceebe4a..96d65f781 100644
--- a/src/NzbDrone.Core.Test/Profiles/ProfileServiceFixture.cs
+++ b/src/NzbDrone.Core.Test/Profiles/ProfileServiceFixture.cs
@@ -7,6 +7,8 @@ using NzbDrone.Core.Profiles;
 using NzbDrone.Core.Test.Framework;
 using NzbDrone.Core.Movies;
 using NzbDrone.Core.NetImport;
+using NzbDrone.Core.CustomFormats;
+using System.Collections.Generic;
 
 namespace NzbDrone.Core.Test.Profiles
 {
@@ -17,6 +19,10 @@ namespace NzbDrone.Core.Test.Profiles
         [Test]
         public void init_should_add_default_profiles()
         {
+            Mocker.GetMock<ICustomFormatService>()
+                .Setup(s => s.All())
+                .Returns(new List<CustomFormats.CustomFormat>());
+
             Subject.Handle(new ApplicationStartedEvent());
 
             Mocker.GetMock<IProfileRepository>()
diff --git a/src/NzbDrone.Core/Profiles/Profile.cs b/src/NzbDrone.Core/Profiles/Profile.cs
index 2e51f3dcd..4bdf4cc86 100644
--- a/src/NzbDrone.Core/Profiles/Profile.cs
+++ b/src/NzbDrone.Core/Profiles/Profile.cs
@@ -17,7 +17,7 @@ namespace NzbDrone.Core.Profiles
         public string Name { get; set; }
         public int Cutoff { get; set; }
         public List<ProfileQualityItem> Items { get; set; }
-        public CustomFormat FormatCutoff { get; set; }
+        public int FormatCutoff { get; set; }
         public List<ProfileFormatItem> FormatItems { get; set; }
         public List<string> PreferredTags { get; set; }
         public Language Language { get; set; }
diff --git a/src/NzbDrone.Core/Profiles/ProfileFormatItem.cs b/src/NzbDrone.Core/Profiles/ProfileFormatItem.cs
index 2d031674c..73b37b45b 100644
--- a/src/NzbDrone.Core/Profiles/ProfileFormatItem.cs
+++ b/src/NzbDrone.Core/Profiles/ProfileFormatItem.cs
@@ -1,10 +1,13 @@
-using NzbDrone.Core.CustomFormats;
+using Newtonsoft.Json;
+using NzbDrone.Core.CustomFormats;
 using NzbDrone.Core.Datastore;
 
 namespace NzbDrone.Core.Profiles
 {
     public class ProfileFormatItem : IEmbeddedDocument
     {
+        [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
+        public int Id { get; set; }
         public CustomFormat Format { get; set; }
         public bool Allowed { get; set; }
     }
diff --git a/src/NzbDrone.Core/Profiles/ProfileService.cs b/src/NzbDrone.Core/Profiles/ProfileService.cs
index 4453302b0..080cbb379 100644
--- a/src/NzbDrone.Core/Profiles/ProfileService.cs
+++ b/src/NzbDrone.Core/Profiles/ProfileService.cs
@@ -74,9 +74,9 @@ namespace NzbDrone.Core.Profiles
             foreach (var profile in all)
             {
                 profile.FormatItems = profile.FormatItems.Where(c => c.Format.Id != formatId).ToList();
-                if (profile.FormatCutoff.Id == formatId)
+                if (profile.FormatCutoff == formatId)
                 {
-                    profile.FormatCutoff = CustomFormat.None;
+                    profile.FormatCutoff = CustomFormat.None.Id;
                 }
 
                 Update(profile);
@@ -187,7 +187,9 @@ namespace NzbDrone.Core.Profiles
         public Profile GetDefaultProfile(string name, Quality cutoff = null, params Quality[] allowed)
         {
             var groupedQualites = Quality.DefaultQualityDefinitions.GroupBy(q => q.Weight);
+            var formats = _formatService.All();
             var items = new List<ProfileQualityItem>();
+            var formatItems = new List<ProfileFormatItem>();
             var groupId = 1000;
             var profileCutoff = cutoff == null ? Quality.Unknown.Id : cutoff.Id;
 
@@ -223,23 +225,36 @@ namespace NzbDrone.Core.Profiles
                 groupId++;
             }
 
+            foreach (var format in formats)
+            {
+                formatItems.Add(new ProfileFormatItem
+                {
+                    Id = format.Id,
+                    Format = format,
+                    Allowed = false
+                });
+            }
+
             var qualityProfile = new Profile
             {
                 Name = name,
                 Cutoff = profileCutoff,
                 Items = items,
                 Language = Language.English,
-                FormatCutoff = CustomFormat.None,
+                FormatCutoff = CustomFormat.None.Id,
                 FormatItems = new List<ProfileFormatItem>
                 {
                     new ProfileFormatItem
                     {
+                        Id = 0,
                         Allowed = true,
                         Format = CustomFormat.None
                     }
                 }
             };
 
+            qualityProfile.FormatItems.AddRange(formatItems);
+
             return qualityProfile;
         }
 
diff --git a/src/NzbDrone.Core/Qualities/QualityModelComparer.cs b/src/NzbDrone.Core/Qualities/QualityModelComparer.cs
index 324e334c0..d11972b6d 100644
--- a/src/NzbDrone.Core/Qualities/QualityModelComparer.cs
+++ b/src/NzbDrone.Core/Qualities/QualityModelComparer.cs
@@ -94,5 +94,15 @@ namespace NzbDrone.Core.Qualities
 
             return leftIndicies.Select(i => i.CompareTo(rightIndex)).Sum();
         }
+
+        public int Compare(List<CustomFormat> left, int right)
+        {
+            left = left.WithNone();
+
+            var leftIndicies = GetIndicies(left, _profile);
+            var rightIndex = _profile.FormatItems.FindIndex(v => Equals(v.Format, right));
+
+            return leftIndicies.Select(i => i.CompareTo(rightIndex)).Sum();
+        }
     }
 }
diff --git a/src/Radarr.Api.V2/Profiles/Quality/QualityProfileModule.cs b/src/Radarr.Api.V2/Profiles/Quality/QualityProfileModule.cs
index 40c2d9e44..f2698804d 100644
--- a/src/Radarr.Api.V2/Profiles/Quality/QualityProfileModule.cs
+++ b/src/Radarr.Api.V2/Profiles/Quality/QualityProfileModule.cs
@@ -33,7 +33,7 @@ namespace Radarr.Api.V2.Profiles.Quality
                 return all.Except(ids).Empty();
             }).WithMessage("All Custom Formats and no extra ones need to be present inside your Profile! Try refreshing your browser.");
             SharedValidator.RuleFor(c => c.FormatCutoff)
-                .Must(c => _formatService.All().Select(f => f.Id).Contains(c.Id) || c.Id == CustomFormat.None.Id).WithMessage("The Custom Format Cutoff must be a valid Custom Format! Try refreshing your browser.");
+                .Must(c => _formatService.All().Select(f => f.Id).Contains(c) || c == CustomFormat.None.Id).WithMessage("The Custom Format Cutoff must be a valid Custom Format! Try refreshing your browser.");
 
             GetResourceAll = GetAll;
             GetResourceById = GetById;
diff --git a/src/Radarr.Api.V2/Profiles/Quality/QualityProfileResource.cs b/src/Radarr.Api.V2/Profiles/Quality/QualityProfileResource.cs
index 122a0095c..eed5e4421 100644
--- a/src/Radarr.Api.V2/Profiles/Quality/QualityProfileResource.cs
+++ b/src/Radarr.Api.V2/Profiles/Quality/QualityProfileResource.cs
@@ -6,6 +6,7 @@ using NzbDrone.Core.Parser;
 using NzbDrone.Core.Profiles;
 using NzbDrone.Core.Qualities;
 using NzbDrone.Core.Languages;
+using NzbDrone.Core.CustomFormats;
 
 namespace Radarr.Api.V2.Profiles.Quality
 {
@@ -16,7 +17,7 @@ namespace Radarr.Api.V2.Profiles.Quality
         public int Cutoff { get; set; }
         public string PreferredTags { get; set; }
         public List<QualityProfileQualityItemResource> Items { get; set; }
-        public CustomFormatResource FormatCutoff { get; set; }
+        public int FormatCutoff { get; set; }
         public List<ProfileFormatItemResource> FormatItems { get; set; }
         public Language Language { get; set; }
     }
@@ -36,7 +37,7 @@ namespace Radarr.Api.V2.Profiles.Quality
 
     public class ProfileFormatItemResource : RestResource
     {
-        public CustomFormatResource Format { get; set; }
+        public CustomFormat Format { get; set; }
         public bool Allowed { get; set; }
     }
 
@@ -54,7 +55,7 @@ namespace Radarr.Api.V2.Profiles.Quality
                 Cutoff = model.Cutoff,
                 PreferredTags = model.PreferredTags != null ? string.Join(",", model.PreferredTags) : "",
                 Items = model.Items.ConvertAll(ToResource),
-                FormatCutoff = model.FormatCutoff.ToResource(),
+                FormatCutoff = model.FormatCutoff,
                 FormatItems = model.FormatItems.ConvertAll(ToResource),
                 Language = model.Language
             };
@@ -78,7 +79,7 @@ namespace Radarr.Api.V2.Profiles.Quality
         {
             return new ProfileFormatItemResource
             {
-                Format = model.Format.ToResource(),
+                Format = model.Format,
                 Allowed = model.Allowed
             };
         }
@@ -95,7 +96,7 @@ namespace Radarr.Api.V2.Profiles.Quality
                 Cutoff = resource.Cutoff,
                 PreferredTags = resource.PreferredTags.Split(',').ToList(),
                 Items = resource.Items.ConvertAll(ToModel),
-                FormatCutoff = resource.FormatCutoff.ToModel(),
+                FormatCutoff = resource.FormatCutoff,
                 FormatItems = resource.FormatItems.ConvertAll(ToModel),
                 Language = resource.Language
             };
@@ -119,7 +120,7 @@ namespace Radarr.Api.V2.Profiles.Quality
         {
             return new ProfileFormatItem
             {
-                Format = resource.Format.ToModel(),
+                Format = resource.Format,
                 Allowed = resource.Allowed
             };
         }
diff --git a/src/Radarr.Api.V2/Qualities/CustomFormatModule.cs b/src/Radarr.Api.V2/Qualities/CustomFormatModule.cs
index 10bfd582e..ed2862fae 100644
--- a/src/Radarr.Api.V2/Qualities/CustomFormatModule.cs
+++ b/src/Radarr.Api.V2/Qualities/CustomFormatModule.cs
@@ -30,7 +30,7 @@ namespace Radarr.Api.V2.Qualities
                     return !allFormats.Any(f =>
                     {
                         var allTags = f.FormatTags.Select(t => t.Raw.ToLower());
-                        var allNewTags = c.Select(t => t.ToLower());
+                        var allNewTags = c.Split(',').Select(t => t.ToLower());
                         var enumerable = allTags.ToList();
                         var newTags = allNewTags.ToList();
                         return (enumerable.All(newTags.Contains) && f.Id != v.Id && enumerable.Count() == newTags.Count());
diff --git a/src/Radarr.Api.V2/Qualities/CustomFormatResource.cs b/src/Radarr.Api.V2/Qualities/CustomFormatResource.cs
index 4718cfbfc..ce225803f 100644
--- a/src/Radarr.Api.V2/Qualities/CustomFormatResource.cs
+++ b/src/Radarr.Api.V2/Qualities/CustomFormatResource.cs
@@ -8,7 +8,7 @@ namespace Radarr.Api.V2.Qualities
     public class CustomFormatResource : RestResource
     {
         public string Name { get; set; }
-        public List<string> FormatTags { get; set; }
+        public string FormatTags { get; set; }
         public string Simplicity { get; set; }
     }
 
@@ -20,7 +20,7 @@ namespace Radarr.Api.V2.Qualities
             {
                 Id = model.Id,
                 Name = model.Name,
-                FormatTags = model.FormatTags.Select(t => t.Raw.ToUpper()).ToList(),
+                FormatTags = string.Join(",", model.FormatTags.Select(t => t.Raw.ToUpper()).ToList()),
             };
         }
 
@@ -30,7 +30,7 @@ namespace Radarr.Api.V2.Qualities
             {
                 Id = resource.Id,
                 Name = resource.Name,
-                FormatTags = resource.FormatTags.Select(s => new FormatTag(s)).ToList(),
+                FormatTags = resource.FormatTags.Split(',').Select(s => new FormatTag(s)).ToList()
             };
         }
 
diff --git a/src/Radarr.Api.V2/Qualities/FormatTagValidator.cs b/src/Radarr.Api.V2/Qualities/FormatTagValidator.cs
index 3cf6c94c0..a726324b5 100644
--- a/src/Radarr.Api.V2/Qualities/FormatTagValidator.cs
+++ b/src/Radarr.Api.V2/Qualities/FormatTagValidator.cs
@@ -19,7 +19,7 @@ namespace Radarr.Api.V2.Qualities
                 return false;
             }
 
-            var tags = (IEnumerable<string>) context.PropertyValue;
+            var tags = (IEnumerable<string>) context.PropertyValue.ToString().Split(',');
 
             var invalidTags = tags.Where(t => !FormatTag.QualityTagRegex.IsMatch(t));
 
diff --git a/yarn.lock b/yarn.lock
index d339b4658..8589787ea 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3295,10 +3295,10 @@ esprima@^4.0.0:
   resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
   integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
 
-esprint@0.4.0:
-  version "0.4.0"
-  resolved "https://registry.yarnpkg.com/esprint/-/esprint-0.4.0.tgz#f89c9bace36d90407968a8f9ceb0800ff786aab0"
-  integrity sha1-+JybrONtkEB5aKj5zrCAD/eGqrA=
+esprint@0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/esprint/-/esprint-0.5.0.tgz#25975b855b9df625ce2e32655db6dff1a84bbe36"
+  integrity sha512-TpaXKPy6g1saDqMYwqppZC6C0wQpYQAnhms6829oVvP6XieUbGjQdcNgatGQMihin2bMgE90tmX+1OOPc5tuiw==
   dependencies:
     dnode "^1.2.2"
     fb-watchman "^2.0.0"